这是我参与「第四届青训营 」笔记创作活动的第3天
recyclerview画分割线的方式
一: 在recyclerview的item中增加分割线控件
在item的底部 增加一个控件
eg:
<View
android:layout_width="match_parent"
android:layout_height="5dp"
android:background="@android:color/black" />
二:自定义分割线
getItemOffset方法
自定义一个类 继承自RecyclerView.ItemDecoration
重写 getItemOffset方法就可以实现分割线
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
}
其中重要的参数 是outRect
同过这个参数 我们可以设置recycleview 每个item间距,以此来实现分割线的效果
默认情况下 outRect的四个参数(left,right,top,bottom)均为 0,也就是不偏移。
要想设置偏移的话只需要调用
outRect.set(left,top,right,bottom);
这个矩形的四个参数分别代表这当前item偏移的方向和距离
一图胜千言好吧:(虽然有点抽象)
如图为设置top为80的效果
微信的通讯录就是这种上部偏移的效果哦
还有一个view参数
这个view返回的是 滑动之后现的那一个item,什么意思呢? 就是在滑动的时候即将出现的那一个item
除此之外,这个类能做的事情还有很多,不知道你有没有注意到,我们还有两个方法可以重写
接下来就来介绍
onDraw 和onDrawOver 方法
重写这两个方法,我们要注意 他们调用(绘制)的顺序
onDraw---> recyclerView的item --->onDrawOver
所以在onDraw方法绘制的内容会被recyclerView 的item 盖住
在onDarwOver 方法中绘制的内容会盖住recyclerview的 item
有一种情况特殊情况 :在item与item的间隔区域画内容
如图所示
对于这种情况,由于中间层的recyclerView没有遮挡效果,在 onDraw 和OnDrawOver方法中绘制效果一致
对分割线进行定制
我们要想对分割线进行自我定制,其实就是找到具体每一个分割线(区域)的位置坐标,然后再onDraw或onDrawOver方法进行绘制(为什么两个方法都可以上文有讲解)
但是还有一个问题:我们绘制的内容不会和item一起移动怎么办?
我们对每一个方法都打印一下log,然后滑动屏幕
D/decoration: onDraw:
D/decoration: onDrawOver:
D/decoration: onDraw:
D/decoration: onDrawOver:
.....
可以发现 onDraw 和 onDrawOver 方法是会 被不断调用的 (也就是说我们不用像自定义view那样手动调用invalidate方法),直接动态设置 draw方法里的坐标就可以了
获取动态坐标
注意到我们的两个方法中都有一个parent参数
通过这个参数,我们就可以拿到我们想要的位置和坐标信息
-
parent.getChildCount()
此方法用于获取页面上能够显示的所有子view
注意 并不是所有子 item
-
parent.getChildAdapterPosition(child)
返回某一个子view的位置(position)
-
parent.getDecoratedBoundsWithMargins(child,mBounds)
mBounds 是一个矩形的实例对象
调用这样方法后会将 child ,这个view(包括marjin在内)的坐标信息赋值给mBounds
现在,获取到来了 item 的 position(可以根据数据源获取数据)和坐标信息(可以根据Draw 我们想要的)
for (int i = 0; i < parent.getChildCount(); i++) {
final View child=parent.getChildAt(i);
/* final RecyclerView.LayoutParams params= (RecyclerView.LayoutParams) child.getLayoutParams();
int position =params.getViewLayoutPosition();*/
//此方法也是获取position信息,任选其一即可
int position=parent.getChildAdapterPosition(child);
parent.getDecoratedBoundsWithMargins(child,mBounds);
if (position<5){
c.drawText("xiao long"+position,0,mBounds.top+60,paint);
}
else {
c.drawText("xiao long666"+position,0,mBounds.top+60,paint);
}
}
最后在activity中
recyclerView.addItemDecoration(new MyItemDecoration(this));
当然如果你不想写这些麻烦的代码
你可以直接给RecyclerView的跟布局设置背景 ,这样分割线也自动被填充了
比如我们准备一张美女图片👧
除此之外我们还可以对recyclerview添加标签
下面贴部分关键代码
/**
* @author :yinxiaolong
* @describe :reycylerview分割线
* @data:2022/7/29
*/
public class MyItemDecoration extends RecyclerView.ItemDecoration {
private final Paint TextPaint =new Paint();
private final Paint paint =new Paint();
public MyItemDecoration(Context context){
TextPaint.setColor(Color.parseColor("#a33656"));
paint.setStyle(Paint.Style.STROKE);
}
private final Rect mBounds = new Rect();
@Override
public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.onDraw(c, parent, state);
Log.d("decoration", "onDraw: ");
TextPaint.setTextSize(50);
for (int i = 0; i < parent.getChildCount(); i++) {
final View child=parent.getChildAt(i);
/* final RecyclerView.LayoutParams params= (RecyclerView.LayoutParams) child.getLayoutParams();
int position =params.getViewLayoutPosition();*/
int position=parent.getChildAdapterPosition(child);
parent.getDecoratedBoundsWithMargins(child,mBounds);
if (position<5){
c.drawText("xiao long"+position,0,mBounds.top+60, TextPaint);
}
else {
c.drawText(position+"xiao long",0,mBounds.top+60, TextPaint);
}
}
}
//画标签
@Override
public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
for (int i = 0; i < parent.getChildCount(); i++) {
final View child=parent.getChildAt(i);
/* final RecyclerView.LayoutParams params= (RecyclerView.LayoutParams) child.getLayoutParams();
int position =params.getViewLayoutPosition();*/
int position=parent.getChildAdapterPosition(child);
parent.getDecoratedBoundsWithMargins(child,mBounds);
c.drawRect(mBounds.right-110,mBounds.top+90,mBounds.right-5,mBounds.top+160, paint);
if (position%2==0){
c.drawText("大佬",mBounds.right-110,mBounds.top+150, TextPaint);
}else {
c.drawText("菜鸡",mBounds.right-110,mBounds.top+150, TextPaint);
}
}
Log.d("decoration", "onDrawOver: ");
}
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
outRect.set(0,80,0,0);
}
}
这里adapter 使用了DataBinding
Android dataBinding入门| 青训营笔记 - 掘金 (juejin.cn)
/**
* @author yinxiaolong
* @describe :recyclerviewAdapter
* @data: 2022/7/29
*/
public class recyclerviewAdapter extends RecyclerView.Adapter<recyclerviewAdapter.MyViewHolder> {
private List<String> lists;
public recyclerviewAdapter(List<String> list) {
this.lists=list;
}
@NonNull
@Override
public recyclerviewAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
ActivityRecycylerviewItemBinding binding= DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.activity_recycylerview_item,parent,false);
return new MyViewHolder(binding);
}
@Override
public void onBindViewHolder(@NonNull recyclerviewAdapter.MyViewHolder holder, int position) {
String s=lists.get(position);
holder.binding.imageViewItem.setImageResource(R.drawable.ic_launcher_foreground);
holder.getBinding().setString(s);//数据绑定
}
@Override
public int getItemCount() {
return lists.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
ActivityRecycylerviewItemBinding binding;
public MyViewHolder(ActivityRecycylerviewItemBinding binding) {
super(binding.getRoot());
this.binding=binding;
}
public ActivityRecycylerviewItemBinding getBinding(){
return binding;
}
}
}
Activity的代码
public class recyclerviewActivity extends AppCompatActivity {
private ActivityRecyclerviewBinding binding;
private List<String> list=new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding= DataBindingUtil.setContentView(this,R.layout.activity_recyclerview);
LinearLayoutManager linearLayoutManager=new LinearLayoutManager(this);
binding.recyclerView.setLayoutManager(linearLayoutManager);
binding.recyclerView.addItemDecoration(new MyItemDecoration(this));//关键
for (int i = 0; i < 10; i++) {
list.add("xiao long 666");
}
recyclerviewAdapter adapter=new recyclerviewAdapter(list);
binding.recyclerView.setAdapter(adapter);
}
}
写在最后
这里只写了linearLayoutManager的recyclerview,还有很多 布局有不同的方法需要进一步的学习
制造分割线的方法也不仅限于这两种,这只是两种可行的解决方法