RecyclerView remove divider / decorator after the last item

前端 未结 9 2021
礼貌的吻别
礼貌的吻别 2020-12-07 17:46

I have a quite simple RecyclerView.
This is how I set the divider:

DividerItemDecoration itemDecorator = new DividerItemDecoration(getContext(), DividerI         


        
相关标签:
9条回答
  • 2020-12-07 17:50

    The accepted answer doesn't allocate space for decoration as it does not override getItemOffsets()

    I have tweaked the DividerItemDecoration from support library to exclude the decoration from the last item

    public class DividerItemDecorator extends RecyclerView.ItemDecoration {
    
        private Drawable mDivider;
        private final Rect mBounds = new Rect();
    
        public DividerItemDecorator(Drawable divider) {
            mDivider = divider;
        }
    
        @Override
        public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
            canvas.save();
            final int left;
            final int right;
            if (parent.getClipToPadding()) {
                left = parent.getPaddingLeft();
                right = parent.getWidth() - parent.getPaddingRight();
                canvas.clipRect(left, parent.getPaddingTop(), right,
                        parent.getHeight() - parent.getPaddingBottom());
            } else {
                left = 0;
                right = parent.getWidth();
            }
    
            final int childCount = parent.getChildCount();
            for (int i = 0; i < childCount - 1; i++) {
                final View child = parent.getChildAt(i);
                parent.getDecoratedBoundsWithMargins(child, mBounds);
                final int bottom = mBounds.bottom + Math.round(child.getTranslationY());
                final int top = bottom - mDivider.getIntrinsicHeight();
                mDivider.setBounds(left, top, right, bottom);
                mDivider.draw(canvas);
            }
            canvas.restore();
        }
    
        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
    
            if (parent.getChildAdapterPosition(view) == state.getItemCount() - 1) {
                outRect.setEmpty();
            } else
                outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
        }
    }
    

    To apply the decorator, use

    RecyclerView.ItemDecoration dividerItemDecoration = new DividerItemDecorator(dividerDrawable);
    recyclerView.addItemDecoration(dividerItemDecoration);
    

    The source for including orientation can be found here https://gist.github.com/abdulalin/146f8ca42aa8322692b15663b8d508ff

    0 讨论(0)
  • 2020-12-07 17:54

    Create your own Divider class (Example here)

    In the code that draws the divider, check first if you are drawing the divider for the last item in the list. If so, don't draw it.

    Just be aware that if you override OnDrawOver it draws on TOP of your view including scrollbars etc. Best to stick to OnDraw. Lots of examples on Google but this is a good tutorial on creating your own decorators.

    0 讨论(0)
  • 2020-12-07 18:01

    If you don't like divider being drawn behind, you can simply copy or extend DividerItemDecoration class and change its drawing behaviour by modifying for (int i = 0; i < childCount; i++) to for (int i = 0; i < childCount - 1; i++)

    Then add your decorator as recyclerView.addItemDecoration(your_decorator);

    Previous solution

    As proposed here you can extend DividerItemDecoration like this:

    recyclerView.addItemDecoration(
        new DividerItemDecoration(context, linearLayoutManager.getOrientation()) {
            @Override
            public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
                int position = parent.getChildAdapterPosition(view);
                // hide the divider for the last child
                if (position == state.getItemCount() - 1) {
                    outRect.setEmpty();
                } else {
                    super.getItemOffsets(outRect, view, parent, state);
                }
            }
        }
    );
    

    @Rebecca Hsieh pointed out:

    This works when your item view in RecyclerView doesn't have a transparent background, for example,

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:background="#ffffff">
        ... 
    </LinearLayout>
    

    DividerItemDecoration.getItemOffsets is called by RecyclerView to measure the child position. This solution will put the last divider behind the last item. Therefore the item view in RecyclerView should have a background to cover the last divider and this makes it look like hidden.

    0 讨论(0)
  • 2020-12-07 18:07

    Here is Kotlin version of accepted answer :

    class DividerItemDecorator(private val divider: Drawable?) : RecyclerView.ItemDecoration() {
    
        override fun onDrawOver(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) {
            val dividerLeft = parent.paddingLeft
            val dividerRight = parent.width - parent.paddingRight
            val childCount = parent.childCount
            for (i in 0..childCount - 2) {
                val child: View = parent.getChildAt(i)
                val params =
                    child.layoutParams as RecyclerView.LayoutParams
                val dividerTop: Int = child.bottom + params.bottomMargin
                val dividerBottom = dividerTop + (divider?.intrinsicHeight?:0)
                divider?.setBounds(dividerLeft, dividerTop, dividerRight, dividerBottom)
                divider?.draw(canvas)
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-07 18:07

    Extension function for Kotlin:

    fun RecyclerView.addItemDecorationWithoutLastDivider() {
    
        if (layoutManager !is LinearLayoutManager)
            return
    
        addItemDecoration(object :
            DividerItemDecoration(context, (layoutManager as LinearLayoutManager).orientation) {
    
            override fun getItemOffsets( outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
                super.getItemOffsets(outRect, view, parent, state)
    
                if (parent.getChildAdapterPosition(view) == state.itemCount - 1)
                    outRect.setEmpty()
                else
                    super.getItemOffsets(outRect, view, parent, state)
            }
        })
    }
    

    You can use it easily:

    recyclerView.addItemDecorationWithoutLastDivider()
    
    0 讨论(0)
  • 2020-12-07 18:09

    Try this Code, it won't show divider for the last item. This method will give you more control over drawing divider.

    public class DividerItemDecorator extends RecyclerView.ItemDecoration {
        private Drawable mDivider;
    
        public DividerItemDecorator(Drawable divider) {
            mDivider = divider;
        }
    
        @Override
        public void onDrawOver(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
            int dividerLeft = parent.getPaddingLeft();
            int dividerRight = parent.getWidth() - parent.getPaddingRight();
    
            int childCount = parent.getChildCount();
            for (int i = 0; i <= childCount - 2; i++) {
                View child = parent.getChildAt(i);
    
                RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
    
                int dividerTop = child.getBottom() + params.bottomMargin;
                int dividerBottom = dividerTop + mDivider.getIntrinsicHeight();
    
                mDivider.setBounds(dividerLeft, dividerTop, dividerRight, dividerBottom);
                mDivider.draw(canvas);
            }
        }
    }
    

    divider.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
        <size
            android:width="1dp"
            android:height="1dp" />
        <solid android:color="@color/grey_300" />
    </shape>
    

    Set your Divider like this:

    RecyclerView.ItemDecoration dividerItemDecoration = new DividerItemDecorator(ContextCompat.getDrawable(context, R.drawable.divider));
    recyclerView.addItemDecoration(dividerItemDecoration);
    
    0 讨论(0)
提交回复
热议问题