1. 程式人生 > >RecyclerView多功能分割線,橫豎分割線,帶padding,允許取消指定分割線

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