效果圖
升級內容
- 初始化無需傳入任何參數,一切都是自動獲取
- 新增外邊框控制,根據參數設置
- 新增帶標題的grid,根據參數設置
具體使用
默認沒有標題,不繪製外邊框
recyclerView.addItemDecoration(new MyDividerItemDecoration().setHasTitle(true).setDrawOuterBorder(true));
全代碼
package cn;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
public class MyDividerItemDecoration extends RecyclerView.ItemDecoration {
//橫向佈局分割線
public static final int HORIZONTAL_DIV = RecyclerView.HORIZONTAL;
//縱向佈局分割線
public static final int VERTICAL_DIV = RecyclerView.VERTICAL;
//表格佈局分割線
public static final int GRID_DIV = 2;
private int mOrientation;
private int mDividerWidth = 0;
private Paint mPaint;
private boolean isDrawOuterBorder = false;//默認不繪製邊框
private boolean hasTitle = false;//是否有標題
/**
* 默認縱向布分割線
*/
public MyDividerItemDecoration() {
this(VERTICAL_DIV);
}
/**
* @param orientation 方向類型
*/
public MyDividerItemDecoration(int orientation) {
this(orientation, Color.parseColor("#EEEEEE"), 2);
}
/**
* @param orientation 方向類型
* @param color 分割線顏色
* @param divWidth 分割線寬度
*/
public MyDividerItemDecoration(int orientation, int color, int divWidth) {
this.setOrientation(orientation);
mDividerWidth = divWidth;
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(color);
mPaint.setStyle(Paint.Style.FILL);
}
private int getRealOrientation(RecyclerView parent) {
RecyclerView.LayoutManager manager = parent.getLayoutManager();
if (manager instanceof GridLayoutManager) {
return GRID_DIV;
} else if (manager instanceof LinearLayoutManager) {
int o = ((LinearLayoutManager) manager).getOrientation();
if (o == RecyclerView.HORIZONTAL) {
return HORIZONTAL_DIV;
} else {
return VERTICAL_DIV;
}
}
return VERTICAL_DIV;
}
@Override
public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
mOrientation = getRealOrientation(parent);
switch (mOrientation) {
case HORIZONTAL_DIV:
//橫向佈局分割線
drawHorizontal(c, parent);
break;
case VERTICAL_DIV:
//縱向佈局分割線
drawVertical(c, parent);
break;
case GRID_DIV:
//表格格局分割線
drawGrid(c, parent);
break;
default:
//縱向佈局分割線
drawVertical(c, parent);
break;
}
}
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
int itemPosition = parent.getChildAdapterPosition(view);
RecyclerView.Adapter mAdapter = parent.getAdapter();
if (mAdapter != null) {
int mChildCount = mAdapter.getItemCount();
mOrientation = getRealOrientation(parent);
switch (mOrientation) {
case HORIZONTAL_DIV:
/**
* 橫向佈局分割線
* <p>
* 如果是第一個Item,則不需要分割線
* </p>
*/
if (itemPosition != 0) {
outRect.set(mDividerWidth, 0, 0, 0);
}
break;
case VERTICAL_DIV:
/**
* 縱向佈局分割線
* <p>
* 如果是第一個Item,則不需要分割線
* </p>
*/
if (itemPosition != 0) {
outRect.set(0, mDividerWidth, 0, 0);
}
break;
case GRID_DIV:
/**
* 表格格局分割線
* <p>
* 1:當是第一個Item的時候,四周全部需要分割線
* 2:當是第一行Item的時候,需要額外添加頂部的分割線
* 3:當是第一列Item的時候,需要額外添加左側的分割線
* 4:默認情況全部添加底部和右側的分割線
* </p>
*/
RecyclerView.LayoutManager mLayoutManager = parent.getLayoutManager();
if (mLayoutManager instanceof GridLayoutManager) {
GridLayoutManager mGridLayoutManager = (GridLayoutManager) mLayoutManager;
int mSpanCount = mGridLayoutManager.getSpanCount();
int top = 0, left = 0, right = 0, bottom = 0;
int realIndex = 0;
if (hasTitle) {
realIndex = itemPosition - 1;
}
int maxRow = mChildCount / mSpanCount + (mChildCount % mSpanCount == 0 ? 0 : 1);
int indexRow = (realIndex + 1) / mSpanCount + ((realIndex + 1) % mSpanCount == 0 ? 0 : 1);
if ((realIndex + 1) <= mSpanCount && isDrawOuterBorder) {
top = mDividerWidth;
}
if (((realIndex + mSpanCount) % mSpanCount) == 0 && isDrawOuterBorder) {
left = mDividerWidth;
}
if ((realIndex + 1) % mSpanCount != 0 || isDrawOuterBorder) {
right = mDividerWidth;
}
if (indexRow != maxRow || isDrawOuterBorder) {
bottom = mDividerWidth;
}
outRect.set(left, top, right, bottom);
}
break;
default:
//縱向佈局分割線
if (itemPosition != (mChildCount - 1)) {
outRect.set(0, 0, 0, mDividerWidth);
}
break;
}
}
}
/**
* 繪製橫向列表分割線
*
* @param c 繪製容器
* @param parent RecyclerView
*/
private void drawHorizontal(Canvas c, RecyclerView parent) {
int mChildCount = parent.getChildCount();
for (int i = 0; i < mChildCount; i++) {
if (i == 0 && !isDrawOuterBorder) continue;
View mChild = parent.getChildAt(i);
drawLeft(c, mChild, parent);
}
}
/**
* 繪製縱向列表分割線
*
* @param c 繪製容器
* @param parent RecyclerView
*/
private void drawVertical(Canvas c, RecyclerView parent) {
int mChildCount = parent.getChildCount();
for (int i = 0; i < mChildCount; i++) {
if (i == 0 && !isDrawOuterBorder) continue;
View mChild = parent.getChildAt(i);
drawTop(c, mChild, parent);
}
}
/**
* 繪製表格類型分割線
*
* @param c 繪製容器
* @param parent RecyclerView
*/
private void drawGrid(Canvas c, RecyclerView parent) {
int mChildCount = parent.getChildCount();
for (int i = 0; i < mChildCount; i++) {
View mChild = parent.getChildAt(i);
RecyclerView.LayoutManager mLayoutManager = parent.getLayoutManager();
if (mLayoutManager instanceof GridLayoutManager) {
GridLayoutManager mGridLayoutManager = (GridLayoutManager) mLayoutManager;
int mSpanCount = mGridLayoutManager.getSpanCount();
int realIndex = 0;
if (hasTitle) {
if (i == 0) {
drawBottom(c, mChild, parent);
continue;
}
realIndex = i - 1;
}
if ((realIndex + 1) <= mSpanCount && isDrawOuterBorder) {
drawTop(c, mChild, parent);
}
if (((realIndex + mSpanCount) % mSpanCount) == 0 && isDrawOuterBorder) {
drawLeft(c, mChild, parent);
}
if ((realIndex + 1) % mSpanCount != 0 || isDrawOuterBorder) {
drawRight(c, mChild, parent);
}
int maxRow = mChildCount / mSpanCount + (mChildCount % mSpanCount == 0 ? 0 : 1);
int indexRow = (realIndex + 1) / mSpanCount + ((realIndex + 1) % mSpanCount == 0 ? 0 : 1);
if (indexRow != maxRow || isDrawOuterBorder) {
drawBottom(c, mChild, parent);
}
}
}
}
/**
* 繪製右邊分割線
*
* @param c 繪製容器
* @param mChild 對應ItemView
* @param recyclerView RecyclerView
*/
private void drawLeft(Canvas c, View mChild, RecyclerView recyclerView) {
RecyclerView.LayoutParams mChildLayoutParams = (RecyclerView.LayoutParams) mChild.getLayoutParams();
int left = mChild.getLeft() - mDividerWidth - mChildLayoutParams.leftMargin;
int top = mChild.getTop() - mChildLayoutParams.topMargin;
int right = mChild.getLeft() - mChildLayoutParams.leftMargin;
int bottom;
if (isGridLayoutManager(recyclerView)) {
bottom = mChild.getBottom() + mChildLayoutParams.bottomMargin + mDividerWidth;
} else {
bottom = mChild.getBottom() + mChildLayoutParams.bottomMargin;
}
c.drawRect(left, top, right, bottom, mPaint);
}
/**
* 繪製頂部分割線
*
* @param c 繪製容器
* @param mChild 對應ItemView
* @param recyclerView RecyclerView
*/
private void drawTop(Canvas c, View mChild, RecyclerView recyclerView) {
RecyclerView.LayoutParams mChildLayoutParams = (RecyclerView.LayoutParams) mChild.getLayoutParams();
int left;
int top = mChild.getTop() - mChildLayoutParams.topMargin - mDividerWidth;
int right = mChild.getRight() + mChildLayoutParams.rightMargin;
int bottom = mChild.getTop() - mChildLayoutParams.topMargin;
if (isGridLayoutManager(recyclerView)) {
left = mChild.getLeft() - mChildLayoutParams.leftMargin - mDividerWidth;
} else {
left = mChild.getLeft() - mChildLayoutParams.leftMargin;
}
c.drawRect(left, top, right, bottom, mPaint);
}
/**
* 繪製右邊分割線
*
* @param c 繪製容器
* @param mChild 對應ItemView
* @param recyclerView RecyclerView
*/
private void drawRight(Canvas c, View mChild, RecyclerView recyclerView) {
RecyclerView.LayoutParams mChildLayoutParams = (RecyclerView.LayoutParams) mChild.getLayoutParams();
int left = mChild.getRight() + mChildLayoutParams.rightMargin;
int top;
int right = left + mDividerWidth;
int bottom = mChild.getBottom() + mChildLayoutParams.bottomMargin;
if (isGridLayoutManager(recyclerView)) {
top = mChild.getTop() - mChildLayoutParams.topMargin - mDividerWidth;
} else {
top = mChild.getTop() - mChildLayoutParams.topMargin;
}
c.drawRect(left, top, right, bottom, mPaint);
}
/**
* 繪製底部分割線
*
* @param c 繪製容器
* @param mChild 對應ItemView
* @param recyclerView RecyclerView
*/
private void drawBottom(Canvas c, View mChild, RecyclerView recyclerView) {
RecyclerView.LayoutParams mChildLayoutParams = (RecyclerView.LayoutParams) mChild.getLayoutParams();
int left = mChild.getLeft() - mChildLayoutParams.leftMargin;
int top = mChild.getBottom() + mChildLayoutParams.bottomMargin;
int bottom = top + mDividerWidth;
int right;
if (isGridLayoutManager(recyclerView)) {
right = mChild.getRight() + mChildLayoutParams.rightMargin + mDividerWidth;
} else {
right = mChild.getRight() + mChildLayoutParams.rightMargin;
}
c.drawRect(left, top, right, bottom, mPaint);
}
/**
* 判斷RecyclerView所加載LayoutManager是否爲GridLayoutManager
*
* @param recyclerView RecyclerView
* @return 是GridLayoutManager返回true,否則返回false
*/
private boolean isGridLayoutManager(RecyclerView recyclerView) {
RecyclerView.LayoutManager mLayoutManager = recyclerView.getLayoutManager();
return (mLayoutManager instanceof GridLayoutManager);
}
/**
* 初始化分割線類型
*
* @param orientation 分割線類型
*/
public void setOrientation(int orientation) {
if (mOrientation != HORIZONTAL_DIV && mOrientation != VERTICAL_DIV && mOrientation != GRID_DIV) {
throw new IllegalArgumentException("MyDividerItemDecoration:分割線類型設置異常");
} else {
this.mOrientation = orientation;
}
}
/**
* 是否繪製外邊框
*
* @param isDrawOuterBorder
* @return
*/
public MyDividerItemDecoration setDrawOuterBorder(boolean isDrawOuterBorder) {
this.isDrawOuterBorder = isDrawOuterBorder;
return this;
}
public MyDividerItemDecoration setHasTitle(boolean hasTitle) {
this.hasTitle = hasTitle;
return this;
}
}
知識點
帶標題的RecyclerView,自行百度。