RecyclerView多功能分割线,横竖分割线,带padding,允许取消指定分割线

分割线可以画到RecyllerView的item的padding里,类似于android: clipPadding = “true” 效果。

继承自ItemDecoration类,代码如下:


import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ItemDecoration;
import android.support.v7.widget.RecyclerView.State;
import android.view.View;

import com.codeignis.mylibrary.util.L;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by lu on 2017/8/29 16:07
 */
public class MultiItemDivider extends 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;
    private Drawable mDivider;
    private int mOrientation;


    //    public final static int START = 0x02;//第一个item顶部无偏移,没有实现第一个上方分割线
    public final static int INSIDE = 0x00;
    public final static int END = 0x01;

    private int dividerMode = INSIDE;
    private boolean clipChild;

    public MultiItemDivider(Context context, int orientation) {
        final TypedArray a = context.obtainStyledAttributes(ATTRS);
        Drawable divider = a.getDrawable(0);
        init(orientation, divider);
        a.recycle();
    }

    public MultiItemDivider(Context context, int orientation, int drawableId) {
        Drawable divider = null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            divider = context.getDrawable(drawableId);
        } else {
            divider = context.getResources().getDrawable(drawableId);
        }
        init(orientation, divider);
    }

    public MultiItemDivider(Context context, int orientation, Drawable divider) {
        init(orientation, divider);
    }

    private void init(int orientation, Drawable divider) {
        mDivider = divider;
        exceptList = new ArrayList<>();
        setOrientation(orientation);
    }

    public void setOrientation(int orientation) {
        if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
            throw new IllegalArgumentException("invalid orientation");
        }
        mOrientation = orientation;
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        if (mOrientation == HORIZONTAL_LIST) {//以recyclerView的布局设置为标准
            drawHorizontal(c, parent);
        } else {
            drawVertical(c, parent);
        }
    }

    /**
     * 获取分割线模式
     * @return {@link #INSIDE },{@link #END}
     */
    public int getDividerMode() {
        return dividerMode;
    }
    /**
     * 设置分割线模式
     * @param dividerMode {@link #INSIDE } or {@link #END}
     */
    public void setDividerMode(int dividerMode) {
        this.dividerMode = dividerMode;
    }

    /**
     * 是否卷进padding中
     * @param clipChild
     */
    public void clipToChildPadding(boolean clipChild) {
        this.clipChild = clipChild;
    }

    /**
     * 垂直方向分割线(横线)收卷到子view的计算
     * @param child
     * @param left
     * @param top
     * @param right
     * @param bottom
     */
    private void clipChildVertical(View child, int left, int top, int right, int bottom) {
        //同上
        if (clipChild) {
            int l = left + child.getPaddingLeft();
            int r = right - child.getPaddingRight();
            int t = top - child.getPaddingBottom();
            int b = bottom - child.getPaddingBottom();
            L.d(">>>", l + " -- " + t + " -- " + r + " -- " + b);
            mDivider.setBounds(l, t, r, b);
        } else {
            mDivider.setBounds(left, top, right, bottom);
        }
    }

    /**
     * 绘制垂直方向分割线(横线)
     * @param c
     * @param parent
     */
    private void drawVertical(Canvas c, RecyclerView parent) {
        final int left = parent.getPaddingLeft();
        final int right = parent.getWidth() - parent.getPaddingRight();

        final int childCount = parent.getChildCount();

        Object layout = parent.getLayoutManager();
        LinearLayoutManager lin = layout instanceof LinearLayoutManager ? ((LinearLayoutManager) layout) : null;

        //下边画线
        if (lin != null && lin.getOrientation() == LinearLayoutManager.HORIZONTAL && dividerMode == END) {
            View child = parent.getChildAt(0);
            if (child == null || exceptList.contains(0)) {

                return;
            }
            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
            int top = child.getBottom() + params.bottomMargin;
            int bottom = top + getDividerOffH(parent,child);
            clipChildVertical(child, left, top, right, bottom);
            mDivider.draw(c);
            return;
        }


        for (int i = 0; i < childCount; i++) {

            final View child = parent.getChildAt(i);


            int position = parent.getChildAdapterPosition(child);
            L.d(">>>", position + "++++");
            if (child == null || exceptList.contains(position)) {
                L.d(">>>", "00000======" + position);
                continue;
            }

            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();

//            if (dividerMode == START) {
//                final int bottom = child.getTop() + params.bottomMargin;
//                final int top = bottom - mDivider.getIntrinsicHeight();
//                ;
//
//                mDivider.setBounds(left, top, right, bottom);
//                mDivider.draw(c);


            final int top = child.getBottom() + params.bottomMargin;
            final int bottom = top + getDividerOffH(parent,child);
            if (dividerMode == END) {
                clipChildVertical(child, left, top, right, bottom);
                mDivider.draw(c);
            } else {//默认绘制 INSIDE
                if (i < childCount - 1) {
                    clipChildVertical(child, left, top, right, bottom);
                    mDivider.draw(c);
                }
            }


        }
    }

    private List<Integer> exceptList;

    /**
     * 添加排除绘制
     * @param index 排除绘制的分割线的索引下标
     */
    public void addExcept(int index) {
        if (exceptList == null) {
            exceptList = new ArrayList<>();
        }
        exceptList.add(index);
    }

    /**
     * 添加排除绘制
     * @param indexList 排除绘制的分割线的索引下标数组
     */
    public void addExcepts(int... indexList) {
        if (indexList == null) {
            return;
        }
        if (exceptList == null) {
            exceptList = new ArrayList<>();
        }
        for (int i = 0; i < indexList.length; i++) {
            exceptList.add(indexList[i]);
        }
    }

    /**
     * 水平方向分割线(竖线)收卷到子view的计算
     * @param child
     * @param left
     * @param top
     * @param right
     * @param bottom
     */
    private void clipHorizontal(View child, int left, int top, int right, int bottom) {

        if (clipChild) {
            int l = left - child.getPaddingRight();
            int r = right - child.getPaddingRight();
            int t = top + child.getPaddingTop();
            int b = bottom - child.getPaddingBottom();
            L.d(">>>", l + " -- " + t + " -- " + r + " -- " + b);
            mDivider.setBounds(l, t, r, b);
        } else {
            mDivider.setBounds(left, top, right, bottom);
        }
    }

    /**
     * 绘制水平方向分割线(竖线)
     * @param c      画布
     * @param parent RecyclerView
     */
    private void drawHorizontal(Canvas c, RecyclerView parent) {
        final int top = parent.getPaddingTop();
        final int bottom = parent.getHeight() - parent.getPaddingBottom();
        final int childCount = parent.getChildCount();

        Object layout = parent.getLayoutManager();
        LinearLayoutManager lin = layout instanceof LinearLayoutManager ? ((LinearLayoutManager) layout) : null;

        //右边画线
        if (lin != null && lin.getOrientation() == LinearLayoutManager.VERTICAL && dividerMode == END) {
            View child = parent.getChildAt(0);
            if (child == null || exceptList.contains(0)) {
                return;
            }
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
            final int left = child.getRight() + params.rightMargin;
            final int right = left + getDividerOffW(parent, child);
            clipHorizontal(child, left, top, right, bottom);
            mDivider.draw(c);
            return;
        }

        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            int position = parent.getChildAdapterPosition(child);
            if (child == null || exceptList.contains(position)) {
                continue;
            }

            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
//            if (dividerMode == START) {
//                final int right = child.getRight() + params.rightMargin;
//                final int left = right - mDivider.getIntrinsicHeight();
//                mDivider.setBounds(left, top, right, bottom);
//                mDivider.draw(c);

            final int left = child.getRight() + params.rightMargin;
            final int right = left + getDividerOffW(parent, child);

            if (dividerMode == END) {
                clipHorizontal(child, left, top, right, bottom);
                mDivider.draw(c);

            } else {//(dividerMode == INSIDE) 和其它值
                if (i < childCount - 1) {
                    clipHorizontal(child, left, top, right, bottom);
                    mDivider.draw(c);
                }
            }
        }
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
        super.getItemOffsets(outRect, view, parent, state);

        if (mOrientation == HORIZONTAL_LIST) {
            outRect.set(0, 0, getDividerOffW(parent,view), 0);
        } else {
            outRect.set(0, 0, 0, getDividerOffH(parent,view));
        }
    }

    private int getDividerOffH(RecyclerView parent,View child) {
        int h = mDivider.getIntrinsicHeight();
        if (h == -1) {
            h = 0;
        }
        if (cleanOffset){
            int position = parent.getChildLayoutPosition(child);
            if (exceptList.contains(position)){
                h = 0;
            }
        }
        return h;
    }

    private int getDividerOffW(RecyclerView parent, View child) {
        int w = mDivider.getIntrinsicWidth();
        if (w == -1) {
            w = 0;
        }
        if (cleanOffset){
            int position = parent.getChildLayoutPosition(child);
            if (exceptList.contains(position)){
                w = 0;
            }
        }
        return w;
    }

    private boolean cleanOffset = true;
    /**
     * 清理未使用的item 装饰,默认清理。offset 位移,装饰view
     * @param c
     */
    public void cleanBlankOffset(boolean c) {
        this.cleanOffset = c;
    }

    /**
     *  清理不绘制列表
     */
    public void clearExpects(){
        if (exceptList!=null){
            exceptList.clear();
        }
    }
}

RecylerView就是一个很普通的RecylerView:

<android.support.v7.widget.RecyclerView
        android:id="@+id/rv_item_pe"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scrollbars="none"
        android:layout_marginTop="@dimen/activity_vertical_margin"
        android:layout_below="@+id/layout_head_item_pe"
        />

它的item 宽充满,但是留有padding:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    xmlns:tools="http://schemas.android.com/tools"
    android:background="@drawable/selector_list"
    android:paddingLeft="16dp"
    >

  <!-- 内容省略 -->

</RelativeLayout>

paddingleft = 16dp,设置分割线收进padding:



        //分割线
        MultiItemDivider itemDivider = new MultiItemDivider(getContext(), MultiItemDivider.VERTICAL_LIST, R.drawable.shape_divider);
//        itemDivider.setDividerMode(MultiItemDivider.INSIDE);//最后一个item下没有分割线
        itemDivider.setDividerMode(MultiItemDivider.END);//最后一个item下有分割线
        itemDivider.addExcepts(itemList.size()-1,itemList.size()-2);//取消倒数第一第二个分割线
        itemDivider.clipToChildPadding(true);//收进padding
        rvItemPe.addItemDecoration(itemDivider);

几种效果预览:

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

第一个图的分割线就收进了padding里。

最后一张图展示,取消了下标为3的分割线。

——end

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值