开篇介绍博客:
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 中的颜色,虽然我没有试过图片,不过,我想应该可以把,不过,应该不会有这种奇葩无敌的需求吧。