Decoración RecyclerView (con GridLayoutManager) para mostrar el divisor entre los elementos

¿Cuál es la mejor y más fácil manera de decorar RecyclerView para tener tal aspecto?

Introduzca aquí la descripción de la imagen

El reto principal aquí es tener divisores sólo entre los elementos, pero no entre los elementos y los bordes izquierdo / derecho de la pantalla.

¿Algunas ideas?

No sé por qué lo necesita, pero esta interfaz de usuario es muy fácil de implementar con RecyclerView decorador.

mRecylerView.addItemDecoration(new ItemDecorationAlbumColumns( getResources().getDimensionPixelSize(R.dimen.photos_list_spacing), getResources().getInteger(R.integer.photo_list_preview_columns))); 

Y decorador (necesita algunas refatoring)

 import android.graphics.Rect; import android.support.v7.widget.RecyclerView; import android.view.View; public class ItemDecorationAlbumColumns extends RecyclerView.ItemDecoration { private int mSizeGridSpacingPx; private int mGridSize; private boolean mNeedLeftSpacing = false; public ItemDecorationAlbumColumns(int gridSpacingPx, int gridSize) { mSizeGridSpacingPx = gridSpacingPx; mGridSize = gridSize; } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { int frameWidth = (int) ((parent.getWidth() - (float) mSizeGridSpacingPx * (mGridSize - 1)) / mGridSize); int padding = parent.getWidth() / mGridSize - frameWidth; int itemPosition = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewAdapterPosition(); if (itemPosition < mGridSize) { outRect.top = 0; } else { outRect.top = mSizeGridSpacingPx; } if (itemPosition % mGridSize == 0) { outRect.left = 0; outRect.right = padding; mNeedLeftSpacing = true; } else if ((itemPosition + 1) % mGridSize == 0) { mNeedLeftSpacing = false; outRect.right = 0; outRect.left = padding; } else if (mNeedLeftSpacing) { mNeedLeftSpacing = false; outRect.left = mSizeGridSpacingPx - padding; if ((itemPosition + 2) % mGridSize == 0) { outRect.right = mSizeGridSpacingPx - padding; } else { outRect.right = mSizeGridSpacingPx / 2; } } else if ((itemPosition + 2) % mGridSize == 0) { mNeedLeftSpacing = false; outRect.left = mSizeGridSpacingPx / 2; outRect.right = mSizeGridSpacingPx - padding; } else { mNeedLeftSpacing = false; outRect.left = mSizeGridSpacingPx / 2; outRect.right = mSizeGridSpacingPx / 2; } outRect.bottom = 0; } } 

Introduzca aquí la descripción de la imagenIntroduzca aquí la descripción de la imagen

Usted puede obtener su respuesta, pero todavía estoy publicando mi solución que puede ayudar a otros. Esto puede usarse para listas verticales, horizontales o vistas de cuadrícula al pasar la orientación.

 import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; public class DividerItemDecoration extends RecyclerView.ItemDecoration { private static final int[] ATTRS = new int[]{ android.R.attr.listDivider }; public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; public static final int GRID = 2; private Drawable mDivider; private int mOrientation; public DividerItemDecoration(Context context, int orientation) { final TypedArray a = context.obtainStyledAttributes(ATTRS); mDivider = a.getDrawable(0); a.recycle(); setOrientation(orientation); } public void setOrientation(int orientation) { if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST && orientation != GRID) { throw new IllegalArgumentException("invalid orientation"); } mOrientation = orientation; } @Override public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { if (mOrientation == VERTICAL_LIST) { drawVertical(c, parent); } else if(mOrientation == HORIZONTAL_LIST){ drawHorizontal(c, parent); } else { drawVertical(c, parent); drawHorizontal(c, parent); } } public void drawVertical(Canvas c, RecyclerView parent) { if (parent.getChildCount() == 0) return; final int left = parent.getPaddingLeft(); final int right = parent.getWidth() - parent.getPaddingRight(); final View child = parent.getChildAt(0); if (child.getHeight() == 0) return; final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); int top = child.getBottom() + params.bottomMargin + mDivider.getIntrinsicHeight(); int bottom = top + mDivider.getIntrinsicHeight(); final int parentBottom = parent.getHeight() - parent.getPaddingBottom(); while (bottom < parentBottom) { mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); top += mDivider.getIntrinsicHeight() + params.topMargin + child.getHeight() + params.bottomMargin + mDivider.getIntrinsicHeight(); bottom = top + mDivider.getIntrinsicHeight(); } } public void drawHorizontal(Canvas c, RecyclerView parent) { final int top = parent.getPaddingTop(); final int bottom = parent.getHeight() - parent.getPaddingBottom(); final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); final int left = child.getRight() + params.rightMargin + mDivider.getIntrinsicHeight(); final int right = left + mDivider.getIntrinsicWidth(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { if (mOrientation == VERTICAL_LIST) { outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); } else if(mOrientation == HORIZONTAL_LIST) { outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); } else { outRect.set(0, 0, mDivider.getIntrinsicWidth(), mDivider.getIntrinsicHeight()); } } } 
  @BindingAdapter({"bind:adapter"}) public static void bind(RecyclerView view, RecyclerView.Adapter<BaseViewHolder> adapter) { view.setLayoutManager(new GridLayoutManager(view.getContext(), 3)); view.addItemDecoration(new SpacesItemDecorationGrid(view.getContext(), 4, 3)); view.setItemAnimator(new DefaultItemAnimator()); view.setAdapter(adapter); } public class SpacesItemDecorationGrid extends RecyclerView.ItemDecoration { private int mSizeGridSpacingPx; private int mGridSize; private boolean mNeedLeftSpacing = false; /** * @param gridSpacingPx * @param gridSize */ SpacesItemDecorationGrid(Context context, int gridSpacingPx, int gridSize) { mSizeGridSpacingPx = (int) Util.convertDpToPixel(gridSpacingPx, context); mGridSize = gridSize; } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { int frameWidth = (int) ((parent.getWidth() - (float) mSizeGridSpacingPx * (mGridSize - 1)) / mGridSize); int padding = parent.getWidth() / mGridSize - frameWidth; int itemPosition = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewAdapterPosition(); int itemCount = parent.getAdapter().getItemCount() - mGridSize; /* if (itemPosition < mGridSize) { outRect.top = mSizeGridSpacingPx; } else { outRect.top = mSizeGridSpacingPx; }*/ outRect.top = mSizeGridSpacingPx; if (itemPosition % mGridSize == 0) { outRect.left = mSizeGridSpacingPx; outRect.right = padding; mNeedLeftSpacing = true; } else if ((itemPosition + 1) % mGridSize == 0) { mNeedLeftSpacing = false; outRect.right = mSizeGridSpacingPx; outRect.left = padding; } else if (mNeedLeftSpacing) { mNeedLeftSpacing = false; outRect.left = mSizeGridSpacingPx - padding; if ((itemPosition + 2) % mGridSize == 0) { outRect.right = mSizeGridSpacingPx - padding; } else { outRect.right = mSizeGridSpacingPx / 2; } } else if ((itemPosition + 2) % mGridSize == 0) { mNeedLeftSpacing = false; outRect.left = mSizeGridSpacingPx / 2; outRect.right = mSizeGridSpacingPx - padding; } else { mNeedLeftSpacing = false; outRect.left = mSizeGridSpacingPx / 2; outRect.right = mSizeGridSpacingPx / 2; } if (itemPosition > itemCount) { outRect.bottom = mSizeGridSpacingPx; } else { outRect.bottom = 0; } } } 

Una solución más sencilla que funcionó para mí. Espero que pueda ser útil.

 class GridItemDecorator(val context: Context, private val spacingDp: Int, private val mGridSize: Int) : RecyclerView.ItemDecoration() { override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { val resources = context.resources val spacingPx = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, spacingDp.toFloat(), resources.displayMetrics) val bit = if (spacingPx > mGridSize) Math.round(spacingPx / mGridSize) else 1 val itemPosition = (view.layoutParams as RecyclerView.LayoutParams).viewAdapterPosition outRect.top = if (itemPosition < mGridSize) 0 else bit * mGridSize outRect.bottom = 0 val rowPosition = itemPosition % mGridSize outRect.left = rowPosition * bit outRect.right = (mGridSize - rowPosition - 1) * bit } } 
  • Detectar inicio de desplazamiento y desplazamiento final en recyclerview
  • RecyclerView no se muestra
  • Recyclerview Sin adaptador conectado; Saltar el diseño
  • RecyclerView desprende la vista todavía visible
  • Creación de secciones dentro de RecyclerView
  • Control de la velocidad de lanzamiento para la vista del reciclador
  • RecyclerView se bloquea cuando "las vistas desechadas o conectadas no se pueden reciclar"
  • Selección única en RecyclerView
  • Android - Cómo detener la recarga de imágenes en Recyclerview al desplazarse
  • Error al inflar la clase android.support.v7.widget.RecyclerView
  • ¿Cómo obtener la Scrollposition en Recyclerview / Layoutmanager?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.