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?
- Soporte RecyclerView no muestra nada hasta que se toca
- Confirmación y eliminación de deshacer en RecyclerView
- RecyclerView - saltar a la posición, luego desplazamiento suave hasta la parte superior
- TableLayout con RecyclerView
- RecyclerView gravedad
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?
- RecyclerView? Android: attr / selectableItemBackground no funciona en los elementos
- Encabezado RecyclerView bajo elementos de Android
- ListSelector para RecyclerView en el dispositivo táctil libre (usando onKey Listener)
- Crear menú de opciones para RecyclerView-Item
- Encabezado pegajoso de Android RecyclerView / Encabezado de sección RecyclerView
- Horizontal RecyclerView con elementos que tienen altura dinámica
- RecyclerView LinearLayoutManager computeVerticalScrollOffset () no devuelve el valor correcto
- ¿Cómo realizar un seguimiento de los elementos seleccionados en un RecyclerView en Android?
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; } }
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 } }