美文网首页
RecyclerView 添加分割线

RecyclerView 添加分割线

作者: 972ac0603088 | 来源:发表于2017-05-16 23:38 被阅读119次

    在平时开发中,一直没有用到 Android提供的ItemDecoration来设置分割线,不太熟悉用法,基本都是写在列表的ViewHolder里,后来翻了一下Google提供的这个ItemDecoration,感觉还是挺好用的,花点时间,记录一下使用方法。

    使用到ItemDecoration,基本步骤

    1.编写一个RecyclerView.ItemDecoration的子类,
    2.重写getItemOffsets方法 和onDraw方法。
    3.为RecyclerView添加一个ItemDecoration。
    其中重点是第二条重写getItemOffsets和onDraw方法。

    1.先来看getItemOffsets方法

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
    super.getItemOffsets(outRect, view, parent, state);
    }
    

    先简单理解这个方法在itemview 上下左右偏移出多少的空间用来画分割线,等下看到具体效果就能明白。
    这个偏移量怎么设置呢,就设置在第一个参数outRect里:
    outRect.set(int left,int top,int right,int bottom);
    这四个参数,分别代表了itmeview的 左,上,右,下的偏移量。
    好了,这个时候推想一下,一个垂直方向的RecyclerView如果想在每个itemView的底部添加一个分割线,是不是就可以利用getItemOffsets方法,在itemView的底部偏移出一个空间来画分割线?
    想法有了,可以试试,先在底部偏移出30px的空间。
    先写一个RecyclerView ,代码如下

    public class RecyClerViewLineActivity extends BaseActivity {
    private RecyclerView mRecyclerView;
    private NameAdapter mNameAdapter;
    private LinearLayoutManager mLinearLayoutManager;
    @Override
    protected void initView() {
    setContentView(R.layout.ac_recy);
    mRecyclerView = (RecyclerView) findViewById(R.id.ac_recy_list_rcy);
    mLinearLayoutManager = new LinearLayoutManager(this  );
    mRecyclerView.setLayoutManager(mLinearLayoutManager);
    mNameAdapter = new NameAdapter(this);
    mRecyclerView.setAdapter(mNameAdapter);
    CustomItemDecoration  mItemDecoration=new CustomItemDecoration(this);
    mRecyclerView.addItemDecoration(mItemDecoration);
    }
    }
    public class CustomItemDecoration extends RecyclerView.ItemDecoration {
    //利用系统属性中的listDivider来添加
    public static final int[] ATRRS = new int[]{
    android.R.attr.listDivider
    };
    private Context mContext;
    private Drawable mDivder;
    public CustomItemDecoration(Context mContext) {
    this.mContext = mContext;
    final TypedArray ta = mContext.obtainStyledAttributes(ATRRS);
    this.mDivder = ta.getDrawable(0);
    ta.recycle();
    }
    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
    super.onDraw(c, parent, 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,30);
    }
    }
    

    简单的一个RecyclerView,每个itemView 有个TextView.

    没有分割线的运行效果 底部偏移了30px的效果

    比对后发现每个itemView底部多出了30px的空间 ,推测出来应该是修改的外边距,所以些分割线的时候,一定要算出精准的距离,否则会影响到写好的Ui效果。
    另外可以测试一下 ,左右上下都修改的效果。

    outRect.set(10,5,15,30);
    
    修改的偏移量为10,5,15,30的效果

    2.知道了getItemOffsets方法后,看现在看一下onDraw方法

     @Override
        public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
            super.onDraw(c, parent, state); 
    
        }
    

    后面两个参数先不看,只看第一个,很明显是传入一个画布,需要我们来画图了。
    接着刚才的需求,我们已经在itemView的下方偏移出了一个30px的高度,需要画一个20px的高度的分割线。
    要画图,得有画布和坐标,画布是给我们了,坐标需要我们算出来。
    结合需求,发现
    1)分割线的left 是一定的,都等于容器的paddingleft。
    2)分割线的right也是一定的,都等于容器的width- 容器的paddingRigth。
    只剩下top和bottom了。
    3)top等于每个itemView的bottom+ 每个itemView的marginBottom(因为是在底部)
    4)bottom等于 刚刚算出来的top+分割线自身的高度。
    好了 ,四个左边都给了可以画图了。

    @Override
        public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
            super.onDraw(c, parent, state);
            //垂直的列表的分割线 ,左边距是一样的,这里减去 父容器才paddingLeft
            int left=parent.getPaddingLeft();
            //同样,右边也是一样的
            int right=parent.getWidth()-parent.getPaddingRight();
            //获取child的count
            int count=parent.getChildCount();
            //循环 获得 top  和 bottom
            for(int i=0;i<count;i++){
                View child=parent.getChildAt(i);
                RecyclerView.LayoutParams lyp =(RecyclerView.LayoutParams)child.getLayoutParams();
                // 获取 child 的底边到父容器的距离,因为分割线在itme的下面,所以这个距离就变成了分割线的距离父容器的 top
                int top=child.getBottom()+lyp.bottomMargin;
                //top再加分割线的高度,等于bottom
                int bottom=top+ 20;  //这里个20是假设的
                mDivder.setBounds(left,top,right,bottom);
                mDivder.draw(c);
            }
    
    
        }
    
    

    看效果

    30px的偏移和20px的分割线

    好到此,垂直方向的分割线已经完成了。

    3.其实根据刚才的推测,横向的RecyclerView的分割线原理也很好推测。(还是以右边偏移30px,分割线20px为列)

    1)首先是偏移方向,需要再itemView的右边 偏移个30px的空间。
    2)分割线的top 是一定的,都等于容器的paddingTop。
    3)分割线的bottom也是一定的,都等于容器的height- 容器的paddingBottom。
    只剩下right和left了。
    4)left等于每个itemView的right+ 每个itemView的marginRight(因为是在右边)
    5)right等于 刚刚算出来的left+分割线自身的宽度。

     @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            super.getItemOffsets(outRect, view, parent, state);
    
                //只在右边 偏移
                outRect.set(0, 0, 30,0);
    
        }
    
    //在onDraw里调用
     private void drawHorizontal(Canvas c, RecyclerView parent) {
            //水平的列表的分割线 ,top是一定的
            int top=parent.getPaddingTop();
            //同样,bottom也是一定的
            int bottom=parent.getHeight()-parent.getPaddingBottom();
    
            //获取child的count
            int count=parent.getChildCount();
            //循环 获得 left  和 right
            for(int i=0;i<count;i++){
                View child=parent.getChildAt(i);
                RecyclerView.LayoutParams lyp =(RecyclerView.LayoutParams)child.getLayoutParams();
                // 获取 child 的右边到父容器的距离,因为分割线在itme的右边,所以这个距离就变成了分割线的距离父容器的 left
                int left=child.getRight()+lyp.rightMargin;
                //left再加分割线的宽度,等于right
                int right=left+ 20px;
                mDivder.setBounds(left,top,right,bottom);
                mDivder.draw(c);
            }
    
    
    
        }
    

    效果

    横向偏移30分割线20

    以上就是在横向和纵向RecyclerView中添加分割线的做法,还可以写一个标识符,将纵向和横向分割符封装在同一个 ItemDecoration中,根据传入的不同值,来显示不同的效果。

    相关文章

      网友评论

          本文标题:RecyclerView 添加分割线

          本文链接:https://www.haomeiwen.com/subject/jxjrxxtx.html