tutorial studio recyclerview que libreria elementos crear construyen cardview card and android android-recyclerview

android - studio - Decorar RecyclerView(con GridLayoutManager) para mostrar el divisor entre los elementos



recyclerview android listview (5)

Aquí hay una implementación más simple y fácil de usar:

public class MediaSpaceDecoration extends RecyclerView.ItemDecoration { private final int spacing; private final List<Integer> allowedViewTypes = Arrays.asList( R.layout.item_image, R.layout.item_blur); public MediaSpaceDecoration(int spacing) { this.spacing = spacing; } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { final int position = parent.getChildAdapterPosition(view); if (!isMedia(parent, position)) { return; } final int totalSpanCount = getTotalSpanCount(parent); int spanSize = getItemSpanSize(parent, position); if (totalSpanCount == spanSize) { return; } outRect.top = isInTheFirstRow(position, totalSpanCount) ? 0 : spacing; outRect.left = isFirstInRow(position, totalSpanCount) ? 0 : spacing / 2; outRect.right = isLastInRow(position, totalSpanCount) ? 0 : spacing / 2; outRect.bottom = 0; // don''t need } private boolean isInTheFirstRow(int position, int spanCount) { return position < spanCount; } private boolean isFirstInRow(int position, int spanCount) { return position % spanCount == 0; } private boolean isLastInRow(int position, int spanCount) { return isFirstInRow(position + 1, spanCount); } private int getTotalSpanCount(RecyclerView parent) { final RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); return layoutManager instanceof GridLayoutManager ? ((GridLayoutManager) layoutManager).getSpanCount() : 1; } private int getItemSpanSize(RecyclerView parent, int position) { final RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); return layoutManager instanceof GridLayoutManager ? ((GridLayoutManager) layoutManager).getSpanSizeLookup().getSpanSize(position) : 1; } private boolean isMedia(RecyclerView parent, int viewPosition) { final RecyclerView.Adapter adapter = parent.getAdapter(); final int viewType = adapter.getItemViewType(viewPosition); return allowedViewTypes.contains(viewType); } }

También outRect antes de configurar el outRect porque tengo varios spanSize s para cada tipo de viewType y necesito agregar un espacio intermedio adicional solo para los allowedViewTypes de vista allowedViewTypes . Puede eliminar fácilmente esa verificación y el código sería aún más simple. Parece esto para mí:

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

El principal desafío aquí es tener divisores solo 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 bastante fácil de implementar con el decorador RecyclerView.

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

y decorador (necesita un poco de refinamiento)

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; } }


Puede obtener su respuesta pero todavía estoy publicando mi solución que puede ayudar a otros. Esto se puede utilizar 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()); } } }


Una solución más simple que funcionó para mí. Espero que pueda ser de utilidad.

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 } }


@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; } } }