在以前,项目中普遍使用ListView,而ListView有个divider属性可以添加分割线,然而这种分割线却显得比较简单,单调。后来,项目中普遍改用Recyclerview,下面我为大家展现Recyclerview分割线的风采。
Recycleview默认是没有分割线的,需要程序猿手动添加,添加分割线的方式有两种:
- 在每个Item布局中添加一个横线作为分割线
- 使用ItemDecoration抽象接口
【方式一】
每个Item布局中添加一个横线作为分割线,布局如下:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#fff000">
<TextView
android:id="@+id/tv_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="20dp"
android:textSize="20sp"
android:textColor="@color/colorAccent"/>
<TextView
android:layout_width="match_parent"
android:layout_height="5dp"
android:background="@color/gray"/>
</LinearLayout>
如图:
图片.png怎么样,是不是很简单?但是,这样做有个弊端,我们需要在代码中隐藏最后一个Item下面的分割线,这样才能有更好的效果,一般添加分割线我们会采用方式二。
【方式二】
ItemDecoration抽象类,源码如下:
public abstract static class ItemDecoration {
public ItemDecoration() {
}
public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
this.onDraw(c, parent);
}
/** @deprecated */
@Deprecated
public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent) {
}
public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
this.onDrawOver(c, parent);
}
/** @deprecated */
@Deprecated
public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent) {
}
/** @deprecated */
@Deprecated
public void getItemOffsets(@NonNull Rect outRect, int itemPosition, @NonNull RecyclerView parent) {
outRect.set(0, 0, 0, 0);
}
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
this.getItemOffsets(outRect, ((RecyclerView.LayoutParams)view.getLayoutParams()).getViewLayoutPosition(), parent);
}
}
我们发现,去除一些过时的方法之后只剩下三个方法,分别是onDraw
、getItemOffsets
、onDrawOver
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state)
public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state)
public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state)
随便举几个例子:
(1)getItemOffsets的使用
outRect.set(0, 0, 0, mDividerHeight)
确定绘制Item的偏移量,四个参数分别代表左、上、右、下偏移量,如果设置分割线只需要配置下便宜即可,类似于将Item设置了mDividerHeight个margin值。
图片.png具体代码如下:
/**
* 绘制RecyclerView的分割线
*/
public class MyRecyclerViewDivider extends RecyclerView.ItemDecoration {
private int mDividerHeight = 0;//分割线的高度
public MyRecyclerViewDivider(int mDividerHeight){
this.mDividerHeight = mDividerHeight;
}
/**
* 实现类似margin的效果
* @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);
outRect.set(0, 0, 0, mDividerHeight);
}
}
mRecyclerView.addItemDecoration(new MyRecyclerViewDivider(10));
效果如下:
图片.png(2)onDraw的使用
onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state)
onDraw是绘制背景,该回调方法有一个Canvas形参,Canvas可以绘制任意背景(矩形,圆形,路径,文字等等)。
您可能会考虑一个问题, RecyclerView可以设置背景,RecyclerView的Item也可以设置背景,那么这个方法到底绘制的是什么背景呢?
答:
onDraw绘制的背景介于以上两者之间。(以上两者:RecyclerView背景和Item背景)
代码如下:
/**
* 绘制RecyclerView的分割线
*/
public class MyRecyclerViewDivider extends RecyclerView.ItemDecoration {
private Paint dividerPaint;
private int mDividerHeight;
public MyRecyclerViewDivider(int dividerHeight) {
this.mDividerHeight = dividerHeight;
dividerPaint = new Paint();
dividerPaint.setColor(Color.BLUE);
dividerPaint.setStyle(Paint.Style.FILL);
}
/**
* 实现类似margin的效果
* @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);
outRect.set(0, 0, 0, mDividerHeight);
}
/**
* 添加Item的背景
*
* @param c
* @param parent
* @param state
*/
@Override
public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
int childCount = parent.getChildCount();
for (int i = 0; i < childCount - 1; i++) {
View view = parent.getChildAt(i);
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
float left = view.getLeft();
float right = view.getRight();
float top = view.getBottom() + lp.bottomMargin;
float bottom = view.getBottom() + mDividerHeight + lp.bottomMargin;
c.drawRect(left, top, right, bottom, dividerPaint == null ? new Paint() : dividerPaint);
}
}
}
mRecyclerView.addItemDecoration(new MyRecyclerViewDivider(10));
效果如下:
图片.png(3)onDrawOver的使用
onDrawOver可以在Item上方绘制(矩形,圆形,路径,文字等等),和onDraw有一定的相似之处,区别是onDraw在Item下方绘制,onDrawOver则在Item上绘制。
下面演示以下一个模拟场景:如果该项已读,那么在右边显示一个已读图片。(当然,也可以作为分割线显示在Item的上方,这里就不演示了)
代码如下:
public class MyRecyclerViewDivider extends RecyclerView.ItemDecoration {
private Paint dividerPaint;
private int mDividerHeight;
private List<PhotoBean> list;
private Context mContext;
public MyRecyclerViewDivider(Context mContext, int dividerHeight, List<PhotoBean> list) {
this.mDividerHeight = dividerHeight;
dividerPaint = new Paint();
dividerPaint.setColor(Color.BLUE);
dividerPaint.setStyle(Paint.Style.FILL);
this.list = list;
this.mContext = mContext;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.set(0, 0, 0, mDividerHeight);
}
@Override
public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.onDrawOver(c, parent, state);
int childCount = parent.getChildCount();
for (int i = 0; i < childCount - 1; i++) {
View child = parent.getChildAt(i);
int position = parent.getChildAdapterPosition(child);
PhotoBean photoBean = list.get(position);
if(photoBean.isRead()){
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), R.mipmap.read, options);
float scale = child.getHeight() / 2.0f / options.outHeight;
bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(mContext.getResources(), R.mipmap.read), (int) (scale * options.outWidth), (int) (scale * options.outWidth), true);
Matrix matrix = new Matrix();
matrix.setTranslate(child.getRight() * 1.0f - bitmap.getWidth() - 10, child.getTop() - (bitmap.getHeight() - child.getHeight()) / 2);
c.drawBitmap(bitmap, matrix, dividerPaint == null ? new Paint() : dividerPaint);
}
}
}
}
mRecyclerView.addItemDecoration(new MyRecyclerViewDivider(MainActivity.this, 10, list));
效果如下:
图片.png以上介绍了添加分割线的两种方式,下面开始介绍其它知识点。
(1)ItemDecoration的组合
您可能已经知道,RecyclerView添加分割线的代码是这样的
mRecyclerView.addItemDecoration(new MyRecyclerViewDivider1());
然而,我们可以添加多个
mRecyclerView.addItemDecoration(new MyRecyclerViewDivider1());
mRecyclerView.addItemDecoration(new MyRecyclerViewDivider2());
mRecyclerView.addItemDecoration(new MyRecyclerViewDivider3());
如果添加多个,不是覆盖,而是MyRecyclerViewDivider1、MyRecyclerViewDivider2、MyRecyclerViewDivider3同时存在。
(2)getItemOffsets和onDrawOver结合实现粘贴头部效果
首先看一下效果
70.gif这种效果已经在越来越多的项目中运用。
代码如下:
/**
* 绘制RecyclerView的分割线
*/
public class MyRecyclerViewDivider extends RecyclerView.ItemDecoration {
private Paint dividerPaint;
private int mDividerHeight;
private List<PhotoBean> list;
private Context mContext;
private Paint.FontMetrics fontMetrics;
public MyRecyclerViewDivider(Context mContext, int dividerHeight, List<PhotoBean> list) {
this.mDividerHeight = dividerHeight;
dividerPaint = new Paint();
dividerPaint.setColor(Color.BLUE);
dividerPaint.setStyle(Paint.Style.FILL);
fontMetrics = new Paint.FontMetrics();
dividerPaint.setTextSize(50);
fontMetrics = dividerPaint.getFontMetrics();
this.list = list;
this.mContext = mContext;
}
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.set(0, mDividerHeight, 0, 0);
}
@Override
public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.onDrawOver(c, parent, state);
int itemCount = state.getItemCount();
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
int position = parent.getChildAdapterPosition(child);
//核心代码--start---
int left = child.getLeft();
int right = child.getRight();
int bottom = child.getBottom();
int top = Math.max(mDividerHeight, child.getTop());
if (position + 1 < itemCount) {
if (bottom < top ) {
top = bottom;
}
}
//核心代码--end---
dividerPaint.setColor(Color.GRAY);
c.drawRect(left, top - mDividerHeight, right, top, dividerPaint);
dividerPaint.setColor(Color.parseColor("#ffffff"));
c.drawText("类型AAAAAg", left + 10, top - fontMetrics.descent - (mDividerHeight - fontMetrics.bottom + fontMetrics.top) / 2, dividerPaint);
}
}
}
以上已经标注了核心代码,非核心代码按需求自由发挥。
[本章完...]
网友评论