RecyclerView
是一个大家常用的列表控件,在列表中不免会出现多种类型的布局,这时adapter
中多种类型的判断就会充满着switch
的坏味道,可怕的是需求变更,增加或修改新的类型时,所有的改动都在adapter
中进行,没有一个良好的扩展性。MutliItem
主要就是解决这些问题,提供了多类型和ViewHolder
创建绑定的管理器,自动进行item type
的计算,这样Adapter
通过依赖倒置与列表中的多类型解耦,还提高了扩展性。有以下特点:
RecyclerView Adapter
设置数据源,不需要做任何封装RecyclerView Adapter
零编码,解放了复杂的Adapter
类DataBinding
,让你清爽的编写列表代码DataBinding
、隐藏域、输入内容验证及是否变化
在Project root
的build.gradle
中添加:
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
在Module
中添加:
dependencies {
compile 'com.github.free46000:MultiItem:0.9.7'
}
这里由于单一和多种类型写法上没有差别,所以就不单独贴出单一类型的列表代码了。 注册多种类型ViewHolderManager
,并为adapter
设置多种类型数据源:
//初始化adapter BaseItemAdapter adapter = new BaseItemAdapter(); //为TextBean数据源注册ViewHolderManager管理类 adapter.register(TextBean.class, new TextViewManager()); //为更多数据源注册ViewHolderManager管理类 adapter.register(ImageTextBean.class, new ImageAndTextManager()); adapter.register(ImageBean.class, new ImageViewManager()); //组装数据源list List<Object> list = new ArrayList<>(); list.add(new TextBean("AAA")); list.add(new ImageBean(R.drawable.img1)); list.add(new ImageTextBean(R.drawable.img2, "BBB" + i)); //为adapter注册数据源list adapter.setDataItems(list); recyclerView.setAdapter(adapter);
ViewHolder
管理类的子类ImageViewManager
类,其他管理类相似,下面贴出本类全部代码,是不是非常清晰:
public class ImageViewManager extends BaseViewHolderManager<ImageBean> { @Override public void onBindViewHolder(BaseViewHolder holder, ImageBean data) { //在指定viewHolder中获取控件为id的view ImageView imageView = getView(holder, R.id.image); imageView.setImageResource(data.getImg()); } @Override protected int getItemLayoutId() { //返回item布局文件id return R.layout.item_image; } }
这是一种特殊的需求,需要在运行时通过数据源中的某个属性,判断加载的布局,典型的就是聊天功能,相同消息数据对应左右两种气泡视图,在此处贴出注册时的关键代码,其他和多种类型列表类似:
//初始化adapter BaseItemAdapter adapter = new BaseItemAdapter(); //为XXBean数据源注册XXManager管理类组合 adapter.register(MessageBean.class, new ViewHolderManagerGroup<MessageBean>(new SendMessageManager(), new ReceiveMessageManager()) { @Override public int getViewHolderManagerIndex(MessageBean itemData) { //根据message判断是否本人发送并返回对应ViewHolderManager的index值 return itemData.getSender().equals(uid) ? 0 : 1; } }); recyclerView.setAdapter(adapter);
点击监听:
adapter.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(BaseViewHolder viewHolder) { //通过viewHolder获取需要的数据 toastUser(String.format("你点击了第%s位置的数据:%s", viewHolder.getItemPosition() , viewHolder.getItemData())); } });
长按监听:
adapter.setOnItemLongClickListener(new OnItemLongClickListener() { @Override public void onItemLongClick(BaseViewHolder viewHolder) { //通过viewHolder获取需要的数据 toastUser(String.format("你长按了第%s位置的数据:%s", viewHolder.getItemPosition() , viewHolder.getItemData())); } });
//开启动画,并取消动画只在第一次加载时展示 adapter.enableAnimation(baseAnimation, false);
下面写下动画相关方法,库中已经默认实现了部分BaseAnimation
,可以通过Demo看到具体效果
/** * 启动加载动画 * * @param animation BaseAnimation * @param isShowAnimWhenFirstLoad boolean 是否只有在第一次展示的时候才使用动画 */ public void enableAnimation(BaseAnimation animation, boolean isShowAnimWhenFirstLoad) /** * 设置动画时长 默认400L */ public void setAnimDuration(long animDuration) /** * 设置动画加速器 默认{@link LinearInterpolator} */ public void setInterpolator(@NonNull Interpolator interpolator)
至此本库的多种类型列表用法已经完成,并没有修改或继承RecyclerView Adapter
类,完全使用默认实现BaseItemAdapter
即可。
ViewHolderManager
提供视图创建绑定等工作ItemTypeManager
找到对应的ViewHolderManager
ViewHolder管理源码类为ViewHolderManager
,使用者会首先注册数据源和本实例的对应关系,由类型管理类提供统一管理。
adapter
调用本类方法的时候传入并做出通用处理ViewHolder
的创建与绑定方法,为了方便后续使用,写了一个简单的BaseViewHolderManager
实现类,请读者根据业务自行决定是否需要使用更灵活的基类,这里贴出需要复写的两个方法,延续了Adapter
中的命名规则,在使用中减少一些认知成本:/** * 创建ViewHolder * {@link android.support.v7.widget.RecyclerView.Adapter#onCreateViewHolder} */ @NonNull public abstract V onCreateViewHolder(@NonNull ViewGroup parent); /** * 为ViewHolder绑定数据 * {@link android.support.v7.widget.RecyclerView.Adapter#onBindViewHolder} * * @param t 数据源 */ public abstract void onBindViewHolder(@NonNull V holder, @NonNull T t);
组合管理源码类为ViewHolderManagerGroup
,本实例需要一个ViewHolderManager
集合,并增加通过数据源指定哪个ViewHolderManager
的方法,使用者同样会注册数据源和本实例的对应关系,由类型管理类对本类中的ViewHolderManager
集合进行统一注册管理。下面贴出关键代码:
private ViewHolderManager[] viewHolderManagers; /** * @param viewHolderManagers 相同数据源对应的所有ViewHolderManager */ public ViewHolderManagerGroup(ViewHolderManager... viewHolderManagers) { if (viewHolderManagers == null || viewHolderManagers.length == 0) { throw new IllegalArgumentException("viewHolderManagers can not be null"); } this.viewHolderManagers = viewHolderManagers; } /** * 根据item数据源中的属性判断应该返回的对应viewHolderManagers的index值 * * @param itemData item数据源 * @return index值应该是在viewHolderManagers数组有效范围内 */ public abstract int getViewHolderManagerIndex(T itemData);
类型管理源码类为ItemTypeManager
,通过数据源className List
和viewHolderManager List
两组集合对类型进行管理,并对Adapter
提供注册和对应关系查找等方法的支持,这里并没有把这个地方设计灵活,如果有一些变化还是希望可以在ViewHolderManager
做出适配。
热门源码