减少30%工作量的AdapterHelper
由来
随着业务需求越来越多,越来越复杂,相应的UI界面随之变化。我相信RecyclerView大家已经用的不陌生了,但是它的繁琐构建,确实是件头疼的事情,特别是viewType特别多,逻辑特别复杂的情况,过几个月,你确定还能理清思路吗?假设我们服务端是多个接口返回数据,你确定能正确刷新相应type吗?想一个RecyclerView高效快捷管理整个界面吗?你还在使用notifyDataSetChanged无脑刷新吗?如果你迟疑了,那你不妨试试本库。
特点
- 与Adapter为组合关系
- 一行代码刷新相应viewType
- 支持facebook的shimmer加载效果
- 支持粘性头
- 支持异步刷新,可扩展(如配合RxAndroid)
效果
Rx线性排布
一般线性排布
方格排布
关键字高亮
解析
与Adapter为组合关系
最初是直接继承Adapter,但是Java限制单继承,现在Adapter分支太多,可能每个公司都有自己的封装Adapter,避免不必要的修改代码,这里提供组合关系管理Adapter。
public CommonHelperAdapter(RecyclerViewAdapterHelper<T> helper) {
mData = helper.getData();
helper.bindAdapter(this);
mHelper = helper;
}
用法很简单,Adapter的数据集合mData依赖于helper的mData,helper绑定相应Adapter,Adapter剩下的实现方法用helper去实现就算完成工作了(具体的可参考DEMO)。是不是很简单?
关于本地实现自己的helper那就更简单了,在实现的Helper中注册相应的数据,具体如下。
public void registerMoudle(@IntRange(from = 0, to = 999) int type, @IntRange(from = 0) int level,
@LayoutRes int layoutResId, @LayoutRes int headerResId)
public void registerMoudleWithShimmer(@IntRange(from = 0, to = 999) int type, @IntRange(from = 0) int level,
@LayoutRes int layoutResId, @LayoutRes int headerResId,
@LayoutRes int shimmerLayoutResId, @LayoutRes int shimmerHeaderLayoutResId)
上边是类型注册(头和数据同时注册),当然肯定还有单数据注册,带有Shimmer的注册可以提供Shimmer效果的loading,具体布局大家可以根据设计师要求修改,这里提供了默认的头和数据loading布局。
到这里构造工作算是完成了,毫无难度,只能说毫无难度。这里有个缺陷就是type和level的范围限制,具体如下:
- level [0,+∞)
- 数据类型 [0,1000)
- 头类型 [-1000,0)
- shimmer数据类型 [-2000,-1000)
- shimmer头类型 [-3000,-2000)
一行代码刷新相应viewType
public void notifyMoudleDataAndHeaderChanged(List<T> data, T header, int type)
public void notifyShimmerDataAndHeaderChanged(int type, @IntRange(from = 1) int dataCount)
还有比这更简单?再自己封装一下,参数都不用这么多- -!其他还提供单头和单数据的刷新,简单的我都不知道说啥了,下一个。
支持facebook的shimmer加载效果
上面的注册和刷新都提到了Shimmer这个关键字,假设你注册了带Shimmer的,那么你可以使用带Shimmer的刷新,具体的loading布局可以在注册的时候提供,关于Shimmer效果,在实现自己的ViewHolder的时候,去实现Shimmer的效果,然后在自己需要的时机调用,非常灵活。如下是DEMO中的例子:
public void startAnim() {
if (itemView instanceof ShimmerFrameLayout) {
((ShimmerFrameLayout) itemView).startShimmerAnimation();
}
}
ShimmerFrameLayout的具体配置可在xml或者ViewHolder的构造函数去配置,具体用法->传送门
友情提示:这里提供简单的ViewHolder封装(CommonViewHolder)和Adapter封装(CommonHelperAdapter),大家不要再写一堆的ViewHolder了。
支持粘性头
recyclerView.addItemDecoration(new StickyHeaderDecoration(adapter));
public StickyHeaderDecoration(StickyHeaderAdapter adapter)
public StickyHeaderDecoration(StickyHeaderAdapter adapter, boolean renderInline)
是的,你没有看错,一行代码搞定,但前提是你的Adapter要实现StickyHeaderAdapter。
public interface StickyHeaderAdapter<T extends RecyclerView.ViewHolder> {
long getHeaderId(int position);
T onCreateHeaderViewHolder(ViewGroup parent);
void onBindHeaderViewHolder(T holder, int position);
}
支持异步刷新,可扩展(如配合RxAndroid)
能快速找到要刷新的数据,这里借用了DiffUtil,具体用法我就不介绍了,但是有个缺陷就是如果数据量过大的时候,计算的时候很费时,因此把它放在线程中不影响用户操作。库中的异步刷新实现是传统的handler方法,但是我把计算和处理结果的接口提供了,大家可以打造自己的异步处理,这里举个DEMO中栗子,利用RxAndroid(这里是2.0)实现:
Flowable.just(new HandleBase<MultiHeaderEntity>(newData, newHeader, type, refreshType))
.onBackpressureDrop()
.observeOn(Schedulers.computation())
.map(new Function<HandleBase<MultiHeaderEntity>, DiffUtil.DiffResult>() {
@Override
public DiffUtil.DiffResult apply(@NonNull HandleBase<MultiHeaderEntity> handleBase) throws Exception {
return handleRefresh(handleBase.getNewData(), handleBase.getNewHeader(), handleBase.getType(), handleBase.getRefreshType());
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<DiffUtil.DiffResult>() {
@Override
public void accept(@NonNull DiffUtil.DiffResult diffResult) throws Exception {
handleResult(diffResult);
}
});
温馨提示: 如果你的Adapter起始并不是你的数据集合,比如你设置headerLayout等,请重写getListUpdateCallback(),在相应的位置刷新,以免数据错乱异常。关于实体类的id为long类型,考虑的是比较效率,大家可以用hashcode,注意冲突,如果勉强不妨自定义DiffCallBack。
关键字高亮
public static CharSequence handleKeyWordHighLight
(String originStr, String keyWord, @ColorInt int hightLightColor)
这里我提供一个静态方法给大家,传原始的字符串,关键字和高亮颜色即可,很多人问这个,索性在库中提供了。
结束
说实话,我都不知道说啥,实现方便快捷,可以配合大多数RecyclerViewAdapter,我最想说的可能就是我希望大家能使用我的库,找出相应的缺陷,不管是代码逻辑还是性能也好,大家共同进步。大家动一动手指头给个star,谢谢了。
gradle依赖
compile 'com.crazysunj:multitypeadapter:1.2.1'
感谢
传送门
github:https://github.com/crazysunj/MultiTypeRecyclerViewAdapter