RecyclerView的分割线 - ItemDecoration

开篇介绍博客:
Android RecyclerView 使用完全解析 体验艺术般的控件 (Hongyang)
RecyclerView可以在xml文件中配置的特别属性 (u013147734的博客)
以上两篇博客,可以先看hy大神的,比较全比较基础一点,然后可以看第二篇博客,介绍的详细一点,不过这两篇博客都没有很详细的介绍 ItemDecoration 这个类,或者说只是给了个代码例子,但是却没有给出详细的思路,看的我一脸懵逼血。


上图:

这里写图片描述

没错,上图中除了toolbar整个画面其实就是一个RecyclerView,我想这样会比较有代表性一点。我想还是先来说一下数据的思路,其实整个数据都是从string.xml中拿出来的:

<string name="location_hot_city_des">热门城市</string>
    <string name="location_hot_area_des">热门景区</string>

    <string-array name="city_hot">
        <item>定位</item>
        <item>北京市</item>
        <item>天津市</item>
        <item>上海市</item>
        <item>重庆市</item>
        <item>沈阳市</item>
        <item>大连市</item>
        <item>长春市</item>
        <item>哈尔滨市</item>
        <item>郑州市</item>
        <item>武汉市</item>
        <item>长沙市</item>
        <item>广州市</item>
        <item>深圳市</item>
        <item>南京市</item>
    </string-array>

    <string-array name="hot_area">
        <item>故宫博物馆</item>
        <item>东方明珠塔</item>
        <item>黄果树瀑布</item>
        <item>黄山风景区</item>
        <item>庐山风景区</item>
        <item>清明上河园</item>
        <item>布达拉宫</item>
        <item>秦始皇陵</item>
        <item>云岗石窟</item>
        <item>镜泊湖</item>
        <item>桃花源</item>
        <item>黄鹤楼</item>
        <item>丽江古城</item>
        <item>乐山大佛</item>
        <item>南京夫子庙</item>
    </string-array>

在这样的xml的数据下,我另外创建了两个简单的数组,其实就是为了添加 热门城市/热门风景,然后把这些数组合并成一个数组:

ArrayUtils.mergeStringArray(
       ArrayUtils.mergeStringArray(new String[]{"", hotCityDes, ""}, hotCity),       ArrayUtils.mergeStringArray(new String[]{"", hotAreaDes, ""}, hotArea)),
public class ArrayUtils {

    private static final String TAG = "ARRAYUTILS";

    /**
     * 合并数组
     *
     * @param str1
     * @param str2
     * @return
     */
    public static String[] mergeStringArray(String[] str1, String[] str2) {
        int strLen1 = str1.length;// 保存第一个数组长度
        int strLen2 = str2.length;// 保存第二个数组长度
        str1 = Arrays.copyOf(str1, strLen1 + strLen2);// 扩容
        System.arraycopy(str2, 0, str1, strLen1, strLen2);// 将第二个数组与第一个数组合并
        TLog.d(TAG, Arrays.toString(str1));
        return str1;
    }

}

我想说的是上面这些内容,都只是为了自定义 ItemDecoration 做准备的,从上面的代码看下来,可以知道:首先, 0,1,2这三个position,就是热门城市那一行,而 0+hotCity.size , 1 + hotCity.size , 2 + hotCity.size,这是热门风景那一行,计算这些坐标是因为从上图中可以很明显看出,他们的分割线的高度是不同的,并且需要注意的是靠近两侧的item的分割线和中间的分割线是不同的(因为,如果相同的话,应该是中间空白处大,而两边小,这个应该比较好理解吧),并且最后一行的分割线和其它的分割线也是不同的,以上,就是自定义的 ItemDecoration 最重要的部分:思路!!!


ItemDecoration:
撇去 draw 方法不看,我们单独来看 getItemOffsets,这个方法有2个不同的参数,有一个已经被废弃了,不过无所谓,这不是重点,这个方法从我介绍的博客上来看:定义分割线的范围。这句话对于刚刚准备自定义分割线的我来讲,真的是太简洁了,简洁到根本不知道它在说什么,那么我的理解是,你可以把这看成定义 “margin”,而getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state)方法中的 outRect则代表的是 item 所在的位置,outRect的 left,top,right,bottom则分别代表着 marginleft/top/right/bottom。好吧其实还是有些抽象,上代码,画图解释:

这就是上图城市选择分割线的所有代码

import android.graphics.Rect;
import android.support.v7.widget.RecyclerView;
import android.view.View;

import yxmj.cjh.yxmj.api.AppConfig;

/**
 * Created by cjh on 16-8-18.
 */
public class LocationSpaceItemDecoration extends RecyclerView.ItemDecoration {

    private int mSpace;
    private String mSpecial_position;

    public LocationSpaceItemDecoration(int space, String special_position) {
        mSpace = space;
        mSpecial_position = special_position;
    }

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

        outRect.left = mSpace / 2;
        outRect.top = mSpace / 3;
        outRect.right = mSpace / 2;
        outRect.bottom = mSpace / 3;

        int position = parent.getChildAdapterPosition(view);
        if (mSpecial_position.contains(AppConfig.HORIZONTAL_LINE + position + AppConfig.HORIZONTAL_LINE)) {
            outRect.top = mSpace;
            outRect.bottom = 0;
        }
        if (position % 3 == 0)
            outRect.left = mSpace;

        if (position % 3 == 2)
            outRect.right = mSpace;

    }
}

mSpace:代表的是一行 item,每个item 中间的距离。
把每个Item所在位置看成一个 outRect,那么正常情况下(也就是中间的item),为了保证水平方向所有间距相同,那么 left 和 right 就得是 mSpace 的一半。

outRect.left = mSpace / 2;//marginLeft = mSpace/2;
        outRect.top = mSpace / 3; // marginTop = mSpace/3;
        outRect.right = mSpace / 2;// marginRight = mSpace/2;
        outRect.bottom = mSpace / 3;// marginBottom = mSpace/3;

mSpecial_position也就是热门城市/风景的位置,那么当处于这个位置的 item,距离顶部要大一点,距离底部要小一点

if (mSpecial_position.contains(AppConfig.HORIZONTAL_LINE + position + AppConfig.HORIZONTAL_LINE)) {
            outRect.top = mSpace;//marginTop = mSpace
            outRect.bottom = 0; //marginBottom = 0;
        }

.如果是左侧的item那么,left = mSpace

 if (position % 3 == 0)
            outRect.left = mSpace;

如果是右侧的item,那么 right = mSpace

  if (position % 3 == 2)
            outRect.right = mSpace;

希望大家看到这里就明白了,如果还不明白,我画了个简单的图(处女座的同学请忽视,继续看上面):

这里写图片描述

基本上我想表达的就是这些了,这个时候,你再去看 Hongyang 的博客,我想应该就会清晰点了吧,而 draw 方法,就是使用各种资源把这些margin的位置使用 drawable 去填充,可以是 shape,drawable.xml 中的颜色,虽然我没有试过图片,不过,我想应该可以把,不过,应该不会有这种奇葩无敌的需求吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RecyclerView分割线可以通过设置ItemDecoration来实现。下面是一个示例代码: 首先,创建一个分割线的类,继承自RecyclerView.ItemDecoration: ```java public class DividerItemDecoration extends RecyclerView.ItemDecoration { private Drawable mDivider; public DividerItemDecoration(Context context) { // 获取系统默认的分割线Drawable TypedArray styledAttributes = context.obtainStyledAttributes(new int[]{android.R.attr.listDivider}); mDivider = styledAttributes.getDrawable(0); styledAttributes.recycle(); } @Override public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { int left = parent.getPaddingLeft(); int right = parent.getWidth() - parent.getPaddingRight(); int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { View child = parent.getChildAt(i); RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); int top = child.getBottom() + params.bottomMargin; int bottom = top + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } } ``` 然后,在使用RecyclerView的地方,添加分割线: ```java RecyclerView recyclerView = findViewById(R.id.recyclerView); recyclerView.addItemDecoration(new DividerItemDecoration(this)); ``` 这样就可以在RecyclerView的每个Item之间添加一个默认的分割线了。如果需要自定义分割线的样式,可以修改DividerItemDecoration类中的绘制逻辑或者使用其他Drawable替代mDivider。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值