美文网首页
RecyclerView自定义分割线

RecyclerView自定义分割线

作者: 苏苏苏苏考拉 | 来源:发表于2018-06-06 16:05 被阅读20次

    我们给recyclerView定义分割线时主要实现的三个方法是下面三个。

    public class MyDivider extends RecyclerView.ItemDecoration {
    
        /**
         * 通过outRect设置itemView的偏移长度
         *
         * @param outRect
         * @param view
         * @param parent
         * @param state
         */
        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            super.getItemOffsets(outRect, view, parent, state);
        }
    
    
        /**
         * 绘制图层在itemView以下,如果绘制区域与itemView区域相重叠,会被遮挡
         *
         * @param c
         * @param parent
         * @param state
         */
        @Override
        public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
            super.onDraw(c, parent, state);
        }
    
        /**
         * 绘制在图层的最上层
         *
         * @param c
         * @param parent
         * @param state
         */
        @Override
        public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
            super.onDrawOver(c, parent, state);
        }
    }
    
    

    我们先实现水平或者竖直方向的分割线,实现思路是拿到drawable对象后在ondraw方法的回调里 遍历recyclerView的子childView,对outRect设置的边界绘制我们的drawable对象,可以使用系统的分割线drawable对象。

    public class DividerDecoration extends RecyclerView.ItemDecoration {
    
        private Drawable drawable;
        private int[] attrs = new int[]{android.R.attr.listDivider};
        private int orientation;
    
    
        public DividerDecoration(Context context, int orientation) {
            TypedArray typedArray = context.obtainStyledAttributes(attrs);
            drawable = typedArray.getDrawable(0);
            typedArray.recycle();
            if (orientation != LinearLayoutManager.HORIZONTAL && orientation != LinearLayoutManager.VERTICAL) {
                throw new IllegalArgumentException("设置了不正确的列表方向");
            }
            this.orientation = orientation;
        }
    
        /**
         * 对每个item位移方向的分割位置进行绘制
         *
         * @param c
         * @param parent
         * @param state
         */
        @Override
        public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
            super.onDraw(c, parent, state);
            if (orientation == LinearLayoutManager.HORIZONTAL) {
                drawHorizontal(c, parent);
            } else {
                drawVertical(c, parent);
            }
    
        }
    
    
        private void drawHorizontal(Canvas canvas, RecyclerView recyclerView) {
            for (int i = 0; i < recyclerView.getChildCount(); i++) {
                View childAt = recyclerView.getChildAt(i);
                RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) childAt.getLayoutParams();
                int left = childAt.getRight() + layoutParams.rightMargin + Math.round(ViewCompat.getTranslationX(childAt));
                int top = childAt.getTop() - layoutParams.topMargin;
                int bottom = childAt.getBottom() + layoutParams.bottomMargin;
                int right = left + drawable.getIntrinsicWidth();
    
                drawable.setBounds(left, top, right, bottom);
                drawable.draw(canvas);
            }
        }
    
    
        private void drawVertical(Canvas canvas, RecyclerView recyclerView) {
            for (int i = 0; i < recyclerView.getChildCount(); i++) {
                View childAt = recyclerView.getChildAt(i);
                RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) childAt.getLayoutParams();
                int left = childAt.getLeft() - layoutParams.leftMargin;
                int right = childAt.getRight() + layoutParams.rightMargin;
                int top = childAt.getBottom() + layoutParams.bottomMargin + Math.round(ViewCompat.getTranslationY(childAt));
                int bottom = top + drawable.getIntrinsicHeight();
    
                drawable.setBounds(left, top, right, bottom);
                drawable.draw(canvas);
            }
        }
    
    
        /**
         * 获取每个item的偏移量
         *
         * @param outRect
         * @param view
         * @param parent
         * @param state
         */
        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            super.getItemOffsets(outRect, view, parent, state);
            if (orientation == LinearLayoutManager.HORIZONTAL) {
                //水平方向
                outRect.set(0, 0, drawable.getIntrinsicWidth(), 0);
            } else {
                //垂直方向
                outRect.set(0, 0, 0, drawable.getIntrinsicHeight());
            }
        }
    }
    

    我们使用系统分割线的效果如下图所示


    image.png

    然而gridLayout的分割线的计算方式就不能如此计算了,我们可以先绘出水平防线的分割线,然后绘制垂直方向的分割线,并且记得加上网格线交叉的并集。
    这次我们使用自定义颜色的分割线,
    在drawable文件夹下新建一个文件

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
    
        <gradient
            android:centerColor="#ff00ff00"
            android:endColor="#ff0000ff"
            android:startColor="#ffff0000"
            android:type="linear"/>
    
        <size
            android:width="10dp"
            android:height="25dp"/>
    
    </shape> 
    

    在样式文件上指定我们的drawable文件

    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
            <!-- Customize your theme here. -->
            <item name="colorPrimary">@color/colorPrimary</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
            <item name="colorAccent">@color/colorAccent</item>
            <item name="android:listDivider">@drawable/bg_recyclerview_divider</item>
        </style>
    
    public class GridDecoration extends RecyclerView.ItemDecoration {
    
        private Drawable drawable;
        private int[] attrs = new int[]{android.R.attr.listDivider};
    
        public GridDecoration(Context context) {
            TypedArray typedArray = context.obtainStyledAttributes(attrs);
            drawable = typedArray.getDrawable(0);
            typedArray.recycle();
        }
    
        @Override
        public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
            super.onDraw(c, parent, state);
            drawHorizontal(c, parent);
            drawVertical(c, parent);
        }
    
        /**
         * 画水平分割线的条目
         *
         * @param canvas
         * @param recyclerView
         */
        private void drawHorizontal(Canvas canvas, RecyclerView recyclerView) {
            for (int i = 0; i < recyclerView.getChildCount(); i++) {
                View childAt = recyclerView.getChildAt(i);
                RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) childAt.getLayoutParams();
                int left = childAt.getRight() + layoutParams.rightMargin;
                int right = left + drawable.getIntrinsicWidth();
                int top = childAt.getTop() - layoutParams.topMargin;
                int bottom = childAt.getBottom() + layoutParams.bottomMargin;
    
                drawable.setBounds(left, top, right, bottom);
                drawable.draw(canvas);
            }
        }
    
        /**
         * 画垂直分割线的条目,需要把缺少的并集补充上
         *
         * @param canvas
         * @param recyclerView
         */
        private void drawVertical(Canvas canvas, RecyclerView recyclerView) {
            for (int i = 0; i < recyclerView.getChildCount(); i++) {
                View childAt = recyclerView.getChildAt(i);
                RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) childAt.getLayoutParams();
                int left = childAt.getLeft() - layoutParams.leftMargin;
                int right = childAt.getRight() + layoutParams.rightMargin + drawable.getIntrinsicWidth();
                int top = childAt.getBottom() + layoutParams.bottomMargin;
                int bottom = top + drawable.getIntrinsicHeight();
                drawable.setBounds(left, top, right, bottom);
                drawable.draw(canvas);
            }
        }
    
        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            super.getItemOffsets(outRect, view, parent, state);
            int bottom = drawable.getIntrinsicHeight();
            int right = drawable.getIntrinsicWidth();
            RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams();
            int viewAdapterPosition = layoutParams.getViewAdapterPosition();
            if (isLastRow(viewAdapterPosition, parent)) {
                //最后一排
                bottom = 0;
            }
            if (isLastColumn(viewAdapterPosition, parent)) {
                //最后一列
                right = 0;
            }
            outRect.set(0, 0, right, bottom);
        }
    
    
        /**
         * 是否是最后一排
         *
         * @return
         */
        private boolean isLastRow(int currentPosition, RecyclerView recyclerView) {
            int spanCount = getSpanCount(recyclerView);
            if (spanCount != -1) {
                int itemCount = recyclerView.getAdapter().getItemCount();
                if (currentPosition + spanCount >= itemCount)
                    return true;
            }
    
            return false;
    
        }
    
        /**
         * 是否是最后一列
         *
         * @return
         */
        private boolean isLastColumn(int currentPosition, RecyclerView recyclerView) {
            int spanCount = getSpanCount(recyclerView);
            if (spanCount != -1) {
                if ((currentPosition + 1) % spanCount == 0)
                    return true;
            }
            return false;
    
        }
    
        /**
         * 获取recycler的列数
         *
         * @param recyclerView
         * @return
         */
        public int getSpanCount(RecyclerView recyclerView) {
            RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
            if (layoutManager instanceof GridLayoutManager) {
                GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
                int spanCount = gridLayoutManager.getSpanCount();
                return spanCount;
            }
            return -1;
        }
    }
    
    

    如图就是我们网格布局的分割线实现效果


    image.png

    相关文章

      网友评论

          本文标题:RecyclerView自定义分割线

          本文链接:https://www.haomeiwen.com/subject/kgwbsftx.html