How to add dividers and spaces between items in RecyclerView?

前端 未结 30 2852
清歌不尽
清歌不尽 2020-11-22 03:27

This is an example of how it could have been done previously in the ListView class, using the divider and dividerHeight parame

相关标签:
30条回答
  • 2020-11-22 04:11

    I have added a line in list item like below

    <View
    android:id="@+id/divider"
    android:layout_width="match_parent"
    android:layout_height="1px"
    android:background="@color/dividerColor"/>
    

    1px will draw the thin line.

    If you want to hide the divider for the last row then divider.setVisiblity(View.GONE); on the onBindViewHolder for the last list Item.

    0 讨论(0)
  • 2020-11-22 04:12

    For those who are looking just for spaces between items in the RecyclerView see my approach where you get equal spaces between all items, except in first and last items where I gave a bigger padding. I only apply padding to left/right in horizontal LayoutManager and to top/bottom in vertical LayoutManager.

    public class PaddingItemDecoration extends RecyclerView.ItemDecoration {
    
        private int mPaddingPx;
        private int mPaddingEdgesPx;
    
        public PaddingItemDecoration(Activity activity) {
            final Resources resources = activity.getResources();
            mPaddingPx = (int) resources.getDimension(R.dimen.paddingItemDecorationDefault);
            mPaddingEdgesPx = (int) resources.getDimension(R.dimen.paddingItemDecorationEdge);
        }
    
        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            super.getItemOffsets(outRect, view, parent, state);
    
            final int itemPosition = parent.getChildAdapterPosition(view);
            if (itemPosition == RecyclerView.NO_POSITION) {
                return;
            }
            int orientation = getOrientation(parent);
            final int itemCount = state.getItemCount();
    
            int left = 0;
            int top = 0;
            int right = 0;
            int bottom = 0;
    
            /** HORIZONTAL */
            if (orientation == LinearLayoutManager.HORIZONTAL) {
                /** all positions */
                left = mPaddingPx;
                right = mPaddingPx;
    
                /** first position */
                if (itemPosition == 0) {
                    left += mPaddingEdgesPx;
                }
                /** last position */
                else if (itemCount > 0 && itemPosition == itemCount - 1) {
                    right += mPaddingEdgesPx;
                }
            }
            /** VERTICAL */
            else {
                /** all positions */
                top = mPaddingPx;
                bottom = mPaddingPx;
    
                /** first position */
                if (itemPosition == 0) {
                    top += mPaddingEdgesPx;
                }
                /** last position */
                else if (itemCount > 0 && itemPosition == itemCount - 1) {
                    bottom += mPaddingEdgesPx;
                }
            }
    
            if (!isReverseLayout(parent)) {
                outRect.set(left, top, right, bottom);
            } else {
                outRect.set(right, bottom, left, top);
            }
        }
    
        private boolean isReverseLayout(RecyclerView parent) {
            if (parent.getLayoutManager() instanceof LinearLayoutManager) {
                LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
                return layoutManager.getReverseLayout();
            } else {
                throw new IllegalStateException("PaddingItemDecoration can only be used with a LinearLayoutManager.");
            }
        }
    
        private int getOrientation(RecyclerView parent) {
            if (parent.getLayoutManager() instanceof LinearLayoutManager) {
                LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
                return layoutManager.getOrientation();
            } else {
                throw new IllegalStateException("PaddingItemDecoration can only be used with a LinearLayoutManager.");
            }
        }
    }
    

    dimens.xml

    <resources>
        <dimen name="paddingItemDecorationDefault">10dp</dimen>
        <dimen name="paddingItemDecorationEdge">20dp</dimen>
    </resources>
    
    0 讨论(0)
  • 2020-11-22 04:12

    We can decorate the items using various decorators attached to the recyclerview such as the DividerItemDecoration:

    Simply use the following ...taken from the answer by EyesClear

    public class DividerItemDecoration extends RecyclerView.ItemDecoration {
    
    private static final int[] ATTRS = new int[]{android.R.attr.listDivider};
    
    private Drawable mDivider;
    
    /**
     * Default divider will be used
     */
    public DividerItemDecoration(Context context) {
        final TypedArray styledAttributes = context.obtainStyledAttributes(ATTRS);
        mDivider = styledAttributes.getDrawable(0);
        styledAttributes.recycle();
    }
    
    /**
     * Custom divider will be used
     */
    public DividerItemDecoration(Context context, int resId) {
        mDivider = ContextCompat.getDrawable(context, resId);
    }
    
    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        int left = parent.getPaddingLeft();
        int right = parent.getWidth() - parent.getPaddingRight();
    
        int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = parent.getChildAt(i);
    
            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
    
            int top = child.getBottom() + params.bottomMargin;
            int bottom = top + mDivider.getIntrinsicHeight();
    
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }
    

    } and then use the above as follows

    RecyclerView.ItemDecoration itemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST);
    recyclerView.addItemDecoration(itemDecoration);
    

    This will display dividers between each item within the list as shown below:

    And for those of who are looking for more details can check out this guide Using the RecyclerView _ CodePath Android Cliffnotes

    Some answers here suggest the use of margins but the catch is that : If you add both top and bottom margins, they will appear both added between items and they will be too large. If you only add either, there will be no margin either at the top or the bottom of the whole list. If you add half of the distance at the top, half at the bottom, the outer margins will be too small.

    Thus, the only aesthetically correct solution is the divider that the system knows where to apply properly: between items but not above or below items.

    Please let me know of any doubts in the comments below :)

    0 讨论(0)
  • 2020-11-22 04:14

    This link worked like a charm for me:

    https://gist.github.com/lapastillaroja/858caf1a82791b6c1a36

    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.util.AttributeSet;
    import android.view.View;
    
    public class DividerItemDecoration extends RecyclerView.ItemDecoration {
    
        private Drawable mDivider;
        private boolean mShowFirstDivider = false;
        private boolean mShowLastDivider = false;
    
    
        public DividerItemDecoration(Context context, AttributeSet attrs) {
            final TypedArray a = context
                    .obtainStyledAttributes(attrs, new int[]{android.R.attr.listDivider});
            mDivider = a.getDrawable(0);
            a.recycle();
        }
    
        public DividerItemDecoration(Context context, AttributeSet attrs, boolean showFirstDivider,
                boolean showLastDivider) {
            this(context, attrs);
            mShowFirstDivider = showFirstDivider;
            mShowLastDivider = showLastDivider;
        }
    
        public DividerItemDecoration(Drawable divider) {
            mDivider = divider;
        }
    
        public DividerItemDecoration(Drawable divider, boolean showFirstDivider,
                boolean showLastDivider) {
            this(divider);
            mShowFirstDivider = showFirstDivider;
            mShowLastDivider = showLastDivider;
        }
    
        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
                RecyclerView.State state) {
            super.getItemOffsets(outRect, view, parent, state);
            if (mDivider == null) {
                return;
            }
            if (parent.getChildPosition(view) < 1) {
                return;
            }
    
            if (getOrientation(parent) == LinearLayoutManager.VERTICAL) {
                outRect.top = mDivider.getIntrinsicHeight();
            } else {
                outRect.left = mDivider.getIntrinsicWidth();
            }
        }
    
        @Override
        public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
            if (mDivider == null) {
                super.onDrawOver(c, parent, state);
                return;
            }
    
            // Initialization needed to avoid compiler warning
            int left = 0, right = 0, top = 0, bottom = 0, size;
            int orientation = getOrientation(parent);
            int childCount = parent.getChildCount();
    
            if (orientation == LinearLayoutManager.VERTICAL) {
                size = mDivider.getIntrinsicHeight();
                left = parent.getPaddingLeft();
                right = parent.getWidth() - parent.getPaddingRight();
            } else { //horizontal
                size = mDivider.getIntrinsicWidth();
                top = parent.getPaddingTop();
                bottom = parent.getHeight() - parent.getPaddingBottom();
            }
    
            for (int i = mShowFirstDivider ? 0 : 1; i < childCount; i++) {
                View child = parent.getChildAt(i);
                RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
    
                if (orientation == LinearLayoutManager.VERTICAL) {
                    top = child.getTop() - params.topMargin;
                    bottom = top + size;
                } else { //horizontal
                    left = child.getLeft() - params.leftMargin;
                    right = left + size;
                }
                mDivider.setBounds(left, top, right, bottom);
                mDivider.draw(c);
            }
    
            // show last divider
            if (mShowLastDivider && childCount > 0) {
                View child = parent.getChildAt(childCount - 1);
                RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
                if (orientation == LinearLayoutManager.VERTICAL) {
                    top = child.getBottom() + params.bottomMargin;
                    bottom = top + size;
                } else { // horizontal
                    left = child.getRight() + params.rightMargin;
                    right = left + size;
                }
                mDivider.setBounds(left, top, right, bottom);
                mDivider.draw(c);
            }
        }
    
        private int getOrientation(RecyclerView parent) {
            if (parent.getLayoutManager() instanceof LinearLayoutManager) {
                LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
                return layoutManager.getOrientation();
            } else {
                throw new IllegalStateException(
                        "DividerItemDecoration can only be used with a LinearLayoutManager.");
            }
        }
    }
    

    Then in your activity:

    mCategoryRecyclerView.addItemDecoration(
        new DividerItemDecoration(this, null));
    

    Or this if you are using a fragment:

    mCategoryRecyclerView.addItemDecoration(
        new DividerItemDecoration(getActivity(), null));
    
    0 讨论(0)
  • 2020-11-22 04:15

    Just add

    recyclerView.addItemDecoration(new DividerItemDecoration(getContext(),
                    DividerItemDecoration.VERTICAL));
    

    Also you may need to add the dependency
    compile 'com.android.support:recyclerview-v7:27.1.0'

    EDIT:

    For customizing it a little bit you can add a custom drawable:

    DividerItemDecoration itemDecorator = new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL);
    itemDecorator.setDrawable(ContextCompat.getDrawable(getContext(), R.drawable.divider));
    

    You are free to use any custom drawable, for instance:

    <shape xmlns:android="http://schemas.android.com/apk/res/android"
           android:shape="rectangle">
        <solid android:color="@color/colorPrimary"/>
        <size android:height="0.5dp"/>
    </shape>
    
    0 讨论(0)
  • 2020-11-22 04:15

    If you want to add same space for items, the simplest way is to add top+left padding for RecycleView and right+bottom margins to card items.

    dimens.xml

    <resources>
        <dimen name="divider">1dp</dimen>
    </resources>
    

    list_item.xml

    <CardView
     android:layout_marginBottom="@dimen/divider"
     android:layout_marginRight="@dimen/divider">
     ...
    </CardView>
    

    list.xml

    <RecyclerView
     android:paddingLeft="@dimen/divider"
     android:paddingTop="@dimen/divider"
    />
    
    0 讨论(0)
提交回复
热议问题