前言
RecyclerView已经推出很久了,由于其高度的可定制性现在被广泛应用,我们常用的功能,如:单条目更新,LayoutManager实现各种炫酷的排列效果,定义个性分割线等
今天学习如何定制一个自己的分割线,让你的列表看起来更好看
内容部分
首先:常规的用法三步走设置布局方式,设置分割线,设置adapter。
本身系统是自带了一个默认的分割线类DividerItemDecoration可以实现和ListView一样的效果。但是我们可能有其他的需求,如我们希望分割线有不同的颜色,这时我们可以通过DividerItemDecoration的setDrawable(Drawable drawable)方法设置一个Drawable进入,如下:
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL); Drawable drawable = getResources().getDrawable(R.drawable.mycoler); dividerItemDecoration.setDrawable(drawable); recyclerView.addItemDecoration(dividerItemDecoration);
通过编写不同的shape可以设置成不同的颜色的线。如图:
特殊情况问题记录
当我在绘制横向滚动的RecyclerView的分割线的时候,出了一个小问题,因为使用shape画的线,获取Drawable的宽度一直为1px导致,无法显示分割线,如果你传入的是一个图片就没问题,我还没找到原因。
描述:RecyclerView高度为100dp,item的高度为50dp,当绘制出竖直方向分割线的时候,item部分分割线未能显示,经过排查发现,分割线是绘制在RecyclerView的view上,item作为子view存在于RecyclerView的容器中,所以导致分割线绘制的一部分被遮挡,此处我使用系统提供的DividerItemDecoration也是效果一致的。如下图:
所绘制的分割线上绘制在RecyclerView的布局上的,这也就解释了,为什么绘制完分割线需要调用getItemOffsets()方法进行位置重新排列了
如何解决这个情况呢?(其实就是自己根据出传入的Drawable宽度处理)
1.给item设置一个padding值就可以了,这样就可以把分割线显示出来了。
2.通过getItemOffsets()方法设置偏移量,让item顺位后移,显示出来分割线即可。
处理后的图片如下:
不过这个问题我会在尝试,找出为什么拿到的宽度数值不正确,如有知道的大佬,望告知,谢谢
定制过程分析
步骤一
初始化一些参数内容,如偏移量,默认的分割线等
public MyItemDecoration(Context context, int orientation, int inset, Drawable drawable) { if (orientation != VERTICAL && orientation != HORIZONTAL) { throw new IllegalArgumentException("请输入正确的参数!"); } this.inset = inset; mOrientation = orientation; mDivider = drawable; if (drawable == null) { final TypedArray a = context.obtainStyledAttributes(ATTRS); mDivider = a.getDrawable(0); a.recycle(); } }
步骤二
绘制部分,通过标识位来区分是垂直方向还是水平方向
@Override public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { if (parent.getLayoutManager() != null && this.mDivider != null) { if (this.mOrientation == VERTICAL) { this.drawVertical(c, parent); } else { this.drawHorizontal(c, parent); } } }
步骤三
绘制垂直或水平的分割线,这里主要是设置Drawable在RecyclerView中的位置。
private void drawHorizontal(Canvas canvas, RecyclerView parent) { int top = parent.getPaddingTop(); int bottom = parent.getHeight() - parent.getPaddingBottom(); int childCount = parent.getChildCount(); for (int i = 0; i < childCount - 1; i++) { View childAt = parent.getChildAt(i); RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) childAt.getLayoutParams(); int left = childAt.getRight() + layoutParams.rightMargin; int right = mDivider.getIntrinsicWidth() + left; mDivider.setBounds(left, top, right, bottom); mDivider.draw(canvas); } } private void drawVertical(Canvas canvas, RecyclerView parent) { int left = parent.getPaddingLeft(); int right = parent.getWidth() - parent.getPaddingRight(); int childCount = parent.getChildCount(); for (int i = 0; i < childCount - 1; i++) { View child = parent.getChildAt(i); RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams(); int top = child.getBottom() + layoutParams.bottomMargin; int bottom = top + mDivider.getIntrinsicHeight(); if (inset > 0) { mDivider.setBounds(left + inset, top, right - inset, bottom); } else { mDivider.setBounds(left, top, right, bottom); } mDivider.draw(canvas); } }
步骤四
因为我们为RecyclerView添加了分割线,所以整体位置要做调整。主要调整的部分就是,在条目中间添加一个分割线,需要对原来的所有条目后移动一个分割线的宽度(高度)。
@Override public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { if (this.mDivider == null) { outRect.set(0, 0, 0, 0); } else { if (this.mOrientation == VERTICAL) { outRect.set(0, 0, 0, this.mDivider.getIntrinsicHeight()); } else { outRect.set(0, 0, this.mDivider.getIntrinsicWidth(), 0); } } }
以上就是基本的步骤的,其实就是参考系统提供的DividerItemDecoration来写就行。其实系统的代码,是最好的实例,所以多读源码对能力的提升很有帮助。
另外一种实现分割线的方式
其实这种方式很简单,就是将分割线放到item布局中。感觉也是不错的方案,毕竟在做条目布局的时候就把这个分割线完成了。
finish以上完毕,有问题谢谢指出。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持自学编程网。
- 本文固定链接: https://zxbcw.cn/post/196240/
- 转载请注明:必须在正文中标注并保留原文链接
- QQ群: PHP高手阵营官方总群(344148542)
- QQ群: Yii2.0开发(304864863)