美文网首页
RecyView添加分割线

RecyView添加分割线

作者: 猪哥哥_ | 来源:发表于2016-09-23 16:26 被阅读354次

    本文来自: 原文

    一、 理解加入分隔线的原理

    在ListView中,Google为我们提供了SetDivider(Drawable divider)这样的方法来设置分隔线,那么在RecyclerView中,Google又为我们提供了什么样的方法去添加分隔线呢?通过查看官方文档,它,提供了:addItemDecoration(RecyclerView.ItemDecoration decor)这个方法了设置分隔线,那问题又来了,RecyclerView.ItemDecoration是什么东西呢?继续查:然后发现如下:它原来是一个类,里面封装了三个方法:

    (1)void getItemOffsets ()
    (2)void onDraw ()
    (3)void onDrawOver ()

    通过上面的三个方法,可以看出,这是要自己直接画上去,准确的说这几个方法是:添加Divider,主要是找到添加Divider的位置, 而Divider是在drawable文件中写好了的。 利用onDraw和onDrawOver都差不多,我们在创建自己的Decoration类继承RecyclerView.ItemDecoration的时候,我们只要重写getItemOffsets(),还有onDraw()和onDrawOver两者其中之一就可以了.
    那getItemOffsets()方法有什么用呢?从字面意思就是Item要偏移, 由于我们在Item和Item之间加入了分隔线,线其实本质就是一个长方形,也是用户自定义的,既然线也有长宽高,就画横线来说,上面的Item加入了分隔线,那下面的Item就要往下平移,平移的量就是分隔线的高度。不理解每关系,后面看代码就容易理解了。
    现在我们知道了如何添加了,就是通过画,那到底是画在哪里呢?画的位置又怎么确定呢?下面看图:


    分隔线的位置图

    我现在拿画横线来说,从上面这个图中,我们很容易就可以看到,我们画分隔线的位置,是在每一个Item的布局之间,注意:是布局之间。
    好了,我们确定了画在哪里,那我们怎么确定画线的具体的坐标位置呢?也就是我们要确定:分隔线的left, top, right, Bottom. 在Adapter中,我们很容易通过parent(这个parent它其实就是我们能看到的部分)获取每一个childView:

    (1)left:parent.getPaddingLeft()
    (2)right: parent. getWidth()-parent.getPaddingRight();
    (3)top : 就是红线的上面:我们通过ChildView.getBottom()来得到这个Item的底部的高度,也就是蓝线位置,蓝线和红线之间间距:就是这个Item布局文件的:layout_marginBottom, 然后top的位置就是两者之和。
    (4)bttom: 就是top加上分隔线的高度:top+线高

    通过上面的解析,你也许知道了加入分隔线的原理,不理解也没有关系,说也不是说得很清楚,下面直接上代码,通过代码来理解。

    二、自定义MyDecoration.java:(继承RecyclerView.ItemDecoration)

    package com.bobzjg.le.recycleviewdemo;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Canvas;
    import android.graphics.Rect;
    import android.graphics.drawable.Drawable;
    import android.support.v7.widget.LinearLayoutManager;
    import android.support.v7.widget.RecyclerView;
    import android.view.View;
    
    /**
     *
     * 自定义的分界线
     * Created by le on 2016/9/23.
     */
    
    public class MyDecoration extends RecyclerView.ItemDecoration {
    
        private Context mContext;
        private Drawable mDivider;
        private int mOrientation;
        public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
        public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
    
        // 我们通过获取系统属性中的listDivider来添加,在系统中的AppTheme中设置
        public static final int[] ATRRS = new int[]{
                android.R.attr.listDivider
        };
    
        public MyDecoration(Context context, int orientation) {
            this.mContext = context;
            final TypedArray ta = context.obtainStyledAttributes(ATRRS);
            this.mDivider = ta.getDrawable(0);
            ta.recycle();
            setOrientation(orientation);
        }
    
        /**
         * 设置屏幕的方向
         * @param orientation
         */
        public void setOrientation(int orientation) {
            if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
                throw new IllegalArgumentException("invalid orientation");
            }
            mOrientation = orientation;
        }
    
        /**
         * 划线
         * @param c
         * @param parent
         * @param state
         */
        @Override
        public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
            if (mOrientation == HORIZONTAL_LIST){
                drawVerticalLine(c, parent, state);
            }else {
                drawHorizontalLine(c, parent, state);
            }
        }
    
        /**
         * 由于Divider也有长宽高,每一个Item需要向下或者向右偏移
         *
         * @param outRect
         * @param view
         * @param parent
         * @param state
         */
        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            if(mOrientation == HORIZONTAL_LIST){
                //画横线,就是往下偏移一个分割线的高度
                outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
            }else {
                //画竖线,就是往右偏移一个分割线的宽度
                outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
            }
        }
    
        /**
         * 画横线, 这里的parent其实是显示在屏幕显示的这部分
         *
         * @param c
         * @param parent
         * @param state
         */
        public void drawHorizontalLine(Canvas c, RecyclerView parent, RecyclerView.State state){
            int left = parent.getPaddingLeft();
            int right = parent.getWidth() - parent.getPaddingRight();
            final int childCount = parent.getChildCount();
            for (int i = 0; i < childCount; i++){
                final View child = parent.getChildAt(i);
    
                //获得child的布局信息
                final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)child.getLayoutParams();
                final int top = child.getBottom() + params.bottomMargin;
                final int bottom = top + mDivider.getIntrinsicHeight();
                mDivider.setBounds(left, top, right, bottom);
                mDivider.draw(c);
                //Log.d("wnw", left + " " + top + " "+right+"   "+bottom+" "+i);
            }
        }
    
        /**
         * 画竖线
         *
         * @param c
         * @param parent
         * @param state
         */
        public void drawVerticalLine(Canvas c, RecyclerView parent, RecyclerView.State state){
            int top = parent.getPaddingTop();
            int bottom = parent.getHeight() - parent.getPaddingBottom();
            final int childCount = parent.getChildCount();
            for (int i = 0; i < childCount; i++){
                final View child = parent.getChildAt(i);
    
                //获得child的布局信息
                final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)child.getLayoutParams();
                final int left = child.getRight() + params.rightMargin;
                final int right = left + mDivider.getIntrinsicWidth();
                mDivider.setBounds(left, top, right, bottom);
                mDivider.draw(c);
            }
        }
    }
    
    

    从上面的代码中,我们还通过系统属性来适应屏幕的横屏和竖屏,然后确定画横的,还是竖的Divider,其实在里面我们做了三件事,第一件是:获取到系统中的listDivider, 我们就是通过它在主题中去设置的,下面第(6)小点看一下代码就知道了。第二件事:就是找到我们需要添加Divider的位置,从onDraw方法中去找到,并将Divider添加进去。第三个是:得到Item的偏移量。

    三、看看我们的MainActivity.java

            recyclerView.setAdapter(adapter);
            recyclerView.addItemDecoration(new MyDecoration(this, MyDecoration.VERTICAL_LIST));
    

    四、自定义分割线

    1. 分隔线Divider的drawable文件:divider..xml

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android" 
       android:shape="rectangle">
       <solid android:color="#7b7a7a"/>
       <size android:height="1dp"/>
    </shape>
    

    我们在这里面,画了一个:rectangle, 给它填充颜色,还有高度,这样就搞定了,高度小,显示出来也是一条线:其实线的本质就是长方形。这里可以根据个人需要,画不同类型的divider


    2. 在styles.xml的AppTheme中,设置listDivider为我们的divider.xml文件:

    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> 
        <item name="android:listDivider">@drawable/divider</item>
    </style>
    

    这样,我们将系统的listDivider设置成我们自定义的divider. 还记得我们在MyDecoration中获取系统的listDivider这个属性吗,这样通过这个属性,我们就可以将我们的divider.xml文件和MyDecoration.java进行关联了。

    相关文章

      网友评论

          本文标题:RecyView添加分割线

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