我们给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
网友评论