前言
RecyclerView.ItemDecoration是用于实现RecyclerView的Item间距,当然除了实现间距更酷炫的是它可以实现一些在间距上绘制各种分割线。绘制分割线也还是一般操作,深度了解后你甚至可以实现各种时间轴,item分组标题等等功能。因为提供了onDraw方法与Canvas,所以在绘制上*度极大,可以让你实现各种天马行空的效果。
主要的三个重写方法
ItemDecoration只有3个重要的重写方法:
- getItemOffsets 用于实现item的上下左右的间距大小
- onDraw 在这个方法里绘制的文字、颜色、图形都会比item更低一层,这些绘制效果如果与item重叠,就会被item遮盖
- onDrawOver 在这个方法绘制的文字、颜色、图形都会比item更高一层,这些绘制效果始终在最上层,不会被遮盖。
我们逐一了解这些方法如何使用。
getItemOffsets
首先先要写一个RecyclerView列表的Demo来进行演示。这里实现了一个item的背景为蓝色的LinearLayoutManager的列表,如下图:
给列表的item增加上边距
代码如下:
public class MainActivity extends AppCompatActivity { private RecyclerView mRecyclerView; private RecyclerViewAdapter mRecyclerViewAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mRecyclerView = findViewById(R.id.recyclerview); mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); mRecyclerViewAdapter = new RecyclerViewAdapter(); mRecyclerView.setAdapter(mRecyclerViewAdapter); addData(); /* 将itemDecoration添加到RecyclerView。 请注意这里是add的,在底层源码里面可以看到ItemDecoration是可以被添加多个的.这里是一个RecyclerView持有ItemDecoration集合。 能添加当然就可以移除,所以对应移除的方法 mRecyclerView.removeItemDecoration();//根据目标移除 mRecyclerView.removeItemDecorationAt();//根据索引index移除 */ mRecyclerView.addItemDecoration(getItemDecoration()); } private RecyclerView.ItemDecoration getItemDecoration() { return new RecyclerView.ItemDecoration() { @Override public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { outRect.top = 20;//这里增加了20的上边距 } }; } private void addData() { List<String> list = new ArrayList<>(); list.add("猎户座"); list.add("织女座"); list.add("天马座"); list.add("天秤座"); list.add("剑鱼座"); list.add("飞马座"); list.add("三角座"); list.add("天琴座"); list.add("蛇夫座"); mRecyclerViewAdapter.refreshData(list); } }
效果图:
举一反三,我们可以给左边添加边距
代码:
private RecyclerView.ItemDecoration getItemDecoration() { return new RecyclerView.ItemDecoration() { @Override public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { outRect.top = 20; outRect.left = 100; } }; }
效果图:
给指定位置的Item设置边距
有时候,我们的边距需求并不是全部item都是要求有的,比如我们需求“第一个item有 50 的上边距与最后一个item要求有 50 的下边距”。我们可以根据getItemOffsets 方法提供的 RecyclerView, RecyclerView.State 这两个值来确定需要实现边距的指定item。
代码:
private RecyclerView.ItemDecoration getItemDecoration() { return new RecyclerView.ItemDecoration() { @Override public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { if (parent.getChildAdapterPosition(view) == 0){ //给第一位的item设置50上边距 outRect.top = 50; return; } if (parent.getChildAdapterPosition(view) == state.getItemCount() -1){ //给最后一位的item设置50下边距 outRect.bottom = 50;
return; } } }; }
效果图:
onDraw
在重写实现getItemOffsets方法给item增加边距后,我们可以在onDraw方法实现一些文字,图标等等效果。
给空白边距里绘制文字
代码:
private RecyclerView.ItemDecoration getItemDecoration() { return new RecyclerView.ItemDecoration() { private Paint paint = new Paint(); @Override public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { outRect.top = 20; } @Override public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { int count = parent.getChildCount(); //获得当前RecyclerView数量 paint.setColor(Color.RED); //设置画笔为红色 paint.setTextSize(20); //设置文字大小 for (int i = 0; i < count; i++) { //遍历全部item View View view = parent.getChildAt(i); int top = view.getTop(); //获得这个item View的top位置 int bottom = view.getBottom(); int left = view.getLeft(); int right = view.getRight(); c.drawText("第" + i, left, top, paint); } } }; }
这里有些人会有一些误区,认为这里返回的canvas是某一个item下的canvas。(我之前有这样的理解)实际上这里返回的canvas是整个RecyclerView的canvas,如果你把坐标值固定死,也是在RecyclerView里面某个位置绘制这个文字或者图像。所以,这里需要你自己获取全部Item的坐标值,用获取到的Item坐标值来绘制你需要位置上的内容。
效果图:
给空白边距里绘制分割线
onDrawOver
End