How to add dividers and spaces between items in RecyclerView?

前端 未结 30 2812
清歌不尽
清歌不尽 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:32

    Taken from a google search, add this ItemDecoration to your RecyclerView:

    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.");
        }
    }
    }
    
    0 讨论(0)
  • 2020-11-22 04:32

    The RecyclerView is a bit different from the ListView. Actually, the RecyclerView needs a ListView like structure in it. For example, a LinearLayout. The LinearLayout has parameters for the dividing each element. In the code below I have a RecyclerView comprised of CardView objects within a LinearLayout with a "padding" that will put some space between items. Make that space really small and you get a line.

    Here's the Recycler view in recyclerview_layout.xml

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
        android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".ToDoList">
    
        <!-- A RecyclerView with some commonly used attributes -->
        <android.support.v7.widget.RecyclerView
            android:id="@+id/todo_recycler_view"
            android:scrollbars="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    
    </RelativeLayout>
    

    And here is what each item looks like (and it shows as divided due to the android:padding in the LinearLayout that surrounds everything.) in another file: cards_layout.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="match_parent"
        android:layout_height="match_parent"
        **android:padding="@dimen/activity_vertical_margin"**>
        <!-- A CardView that contains a TextView -->
        <android.support.v7.widget.CardView
            xmlns:card_view="http://schemas.android.com/apk/res-auto"
            android:id="@+id/card_view"
            android:layout_gravity="center"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:elevation="30dp"
            card_view:cardElevation="3dp">
                <TextView
                    android:id="@+id/info_text"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    />
        </android.support.v7.widget.CardView>
    </LinearLayout>
    
    0 讨论(0)
  • 2020-11-22 04:32

    A really easy solution is to use RecyclerView-FlexibleDivider

    Add dependency:

    compile 'com.yqritc:recyclerview-flexibledivider:1.4.0'
    

    Add to your recyclerview:

    recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(context).build());
    

    And you're done!

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

    Add a margin to your view, it worked for me.

    android:layout_marginTop="10dp"
    

    If you just want to add equal spacing and want to do it in XML, just set padding to your RecyclerView and equal amount of layoutMargin to the item you inflate into your RecyclerView, and let the background color determine the spacing color.

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

    If anyone is looking to only add, say, 10dp spacing between items, you can do so by setting a drawable to DividerItemDecoration:

    DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(
        recyclerView.getContext(),
        layoutManager.getOrientation()
    );
    
    dividerItemDecoration.setDrawable(
        ContextCompat.getDrawable(getContext(), R.drawable.divider_10dp)
    ); 
    

    Where divider_10dpis a drawable resource containing:

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

    I feel like there's a need for a simple, code-based answer that doesn't use XML

    DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL);
    
    ShapeDrawable shapeDrawableForDivider = new ShapeDrawable(new RectShape());
    
    int dividerThickness = // (int) (SomeOtherView.getHeight() * desiredPercent);
    shapeDrawableForDivider.setIntrinsicHeight(dividerThickness);
    shapeDrawableForDivider.setAlpha(0);
    
    dividerItemDecoration.setDrawable(shapeDrawableForDivider);
    
    recyclerView.addItemDecoration(dividerItemDecoration);
    

    I love this answer so much, I re-wrote it in a single-expression Kotlin answer:

        recyclerView.addItemDecoration(DividerItemDecoration(this,DividerItemDecoration.VERTICAL).also { deco ->
            with (ShapeDrawable(RectShape())){
                intrinsicHeight = (resources.displayMetrics.density * 24).toInt()
                alpha = 0
                deco.setDrawable(this)
            }
        })
    

    This does the same thing as @Nerdy's original answer, except it sets the height of the divider to 24dp instead of a percentage of another view's height.

    0 讨论(0)
提交回复
热议问题