大家好,欢迎来到蜗牛君漫聊动态布局框架专题。上篇文章中我们介绍完了框架的核心功能实现,本篇继续介绍剩下的所有功能。
不同类型ViewHolder的动态创建已经完成,接下来我们要实现数据与布局的中间件—适配器(Adapter)。
代码实现:中间件—适配器
Adapter类
需要做到一下几点:
- 继承官方的Adapter类,并传递BaseViewHolder类作为泛型参数;
- 渲染数据的管理
- 实例化ViewHolderFactory
- Adapter四大方法的实现:onCreateViewHolder、onBindVievHolder、getItemCount、getItemViewType
/**
* 职责:
* 1、数据管理
* 2、实例化ViewHolderFactory
* 3、完成四大方法的具体实现
*/
public class RecyclerAdapter extends RecyclerView.Adapter<BaseViewHolder> {
private ViewHolderFactory mFactory;
private List<Object> dataList = new ArrayList<>();
/**
* 使用指定工厂类
*
* @param context
*/
public RecyclerAdapter(Context context) {
this(new ViewHolderFactory(context));
}
/**
* 手动指定工厂类
*
* @param factory
*/
public RecyclerAdapter(ViewHolderFactory factory) {
mFactory = factory;
}
/**
* 创建Item所需要的ViewHolder
*
* @param parent
* @param viewType
* @return
*/
@NonNull
@Override
public BaseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return mFactory.create(viewType, parent);
}
/**
* 将数据与视图进行绑定
*
* @param holder
* @param position
*/
@SuppressWarnings("unchecked")
@Override
public void onBindViewHolder(@NonNull BaseViewHolder holder, int position) {
holder.bindTo(position, dataList.get(position), this);
}
/**
* Item总数
*
* @return
*/
@Override
public int getItemCount() {
return dataList.size();
}
/**
* 返回当前Item的布局类型
*
* @param position
* @return 当前数据类型在索引集合中的下标
*/
@Override
public int getItemViewType(int position) {
return mFactory.itemViewType(dataList.get(position));
}
/**
* 添加数据
*
* @param list
*/
public void addAll(List<?> list) {
dataList.clear();
if (list != null && !list.isEmpty()) {
dataList.addAll(list);
}
notifyDataSetChanged();
}
}
注意:这里有很多的细节没有讲,例如关于参数类型设置:Object、泛型、占位符的选择;这些基础知识需要大家自行补充了,其中的用意也需要大家自己品味一下,这些细节很重要。
代码实现:建造者模式的使用
1、RecyclerConfig
- 创建者模式提供链式调用与组合配置;
- 创建RecyclerView的配置,除去配置RecyclerView的四大元素之外,还要配置绑定数据类型与ViewHolder的关系、自定义ViewHolderFactory、是否支持刷新等等。
public class RecylerConfig {
private RecyclerView.LayoutManager mLayoutMananger;
private RecyclerView.ItemDecoration mItemDecoration;
private RecyclerView.ItemAnimator mItemAnimator;
private ViewHolderFactory mViewHolderFactory;
private Map<Class, Class<? extends BaseViewHolder>> mBoundViewHolder;
private boolean mEnable = true;
public RecyclerView.LayoutManager getLayoutMananger() {
return mLayoutMananger;
}
public RecyclerView.ItemDecoration getItemDecoration() {
return mItemDecoration;
}
public RecyclerView.ItemAnimator getItemAnimator() {
return mItemAnimator;
}
public Map<Class, Class<? extends BaseViewHolder>> getBoundViewHolder() {
return mBoundViewHolder;
}
public boolean enableRefresh() {
return mEnable;
}
public static class Builder {
private RecyclerView.LayoutManager mLayoutMananger;
private RecyclerView.ItemDecoration mItemDecoration;
private RecyclerView.ItemAnimator mItemAnimator;
private ViewHolderFactory mViewHolderFactory;
private Map<Class, Class<? extends BaseViewHolder>> mBoundViewHolder;
private boolean mEnable = true;
public Builder layoutManager(RecyclerView.LayoutManager layoutMananger) {
this.mLayoutMananger = layoutMananger;
return this;
}
public Builder itemDecoration(RecyclerView.ItemDecoration itemDecoration) {
this.mItemDecoration = itemDecoration;
return this;
}
public Builder itemAnimator(RecyclerView.ItemAnimator itemAnimator) {
this.mItemAnimator = itemAnimator;
return this;
}
public Builder viewHolderFactory(ViewHolderFactory viewHolderFactory) {
this.mViewHolderFactory = viewHolderFactory;
return this;
}
public Builder bind(Class valueClassType, Class<? extends BaseViewHolder> viewHolder) {
this.mBoundViewHolder.put(valueClassType, viewHolder);
return this;
}
public Builder enableRefresh(boolean enable) {
this.mEnable = enable;
return this;
}
public RecylerConfig build() {
RecylerConfig config = new RecylerConfig();
config.mLayoutMananger = this.mLayoutMananger;
config.mItemDecoration = this.mItemDecoration;
config.mItemAnimator = this.mItemAnimator;
config.mBoundViewHolder = this.mBoundViewHolder;
config.mViewHolderFactory = this.mViewHolderFactory;
config.mEnable = this.mEnable;
return config;
}
}
}
2、调度 RecyclerViewLayoutActivity.java
// 关联布局文件
@BindView(R.id.recycler_view_layout)
RecyclerView mRecyclerView;
// 主布局
setContentView(R.layout.recycler_view_layout_activity);
// 初始化Adapter
RecyclerAdapter recyclerAdapter = new RecyclerAdapter(this);
// 初始化LayoutManager
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
// 初始化下划线
RecyclerView.ItemDecoration itemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL);
// 通过RecyclerConfig组装RecyclerView配置
RecyclerConfig config = new RecyclerConfig.Builder()
.layoutManager(linearLayoutManager)
.itemDecoration(itemDecoration)
.bind(CommonModel.class, CommonViewHolder.class)
.enableRefresh(false)
.build();
buildConfig(config);
// 进行最终的设置
mRecyclerView.setAdapter(mRecyclerAdapter);
mRecyclerView.setLayoutManager(config.getLayoutMananger());
mRecyclerView.addItemDecoration(config.getItemDecoration());
recycler_view_layout_activity.xml
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="MissingConstraints"
tools:layout_editor_absoluteY="0dp" />
RecyclerView动态布局框架的基础结构讲解完毕,上述框架能够实现基本的布局功能,为了大家读起来更直接,有些封装拆开了平铺展示给大家。最后,给大家总结一下我分析出来的要点。
第一点,思路的根源是RecyclerView能够通过getItemViewType方法动态确定当前Item需要使用的ViewHolder;
第二点:使用Java的反射机制动态创建ViewHolder;
第三点:工厂模式的使用;
第四点:数据类型和ViewHolder一一对应关系的存储方式;
只要大家掌握了上述四点,就能够在RecyclerView的基础使用上封装出适合自己业务的动态布局框架。本篇文章的内容到这里就结束了,通过三篇文章我们将动态布局框架最核心最重要的东西都讲解完了。不过,我们只是实现了通用的功能,还有很多辅助功能还没有实现,因此我们这个专题并不会就此结束,后续文章中我们会介绍监听事件的添加、RecyclerViewAdapter中数据的管理功能、删除某一项、增加某一项功能等等。那就让我们相约下一期吧,再见~