咱们知道在通常的列表视图(recyclerView)中绑定不一样类型的列表项子视图是经过各类类型的ViewHolder
(好比recyclerView.ViewHolder
). 不一样数据对不一样视图控件的操做是以实现各类ViewHolder子类的方式实现的.
能不能只用一种类型的视图来涵盖全部的ViewHolder类型? 听起来有些难以想象, 每种ViewHolder须要绑定的控件千差万别, 怎么抽象这些控件呢? 但其实是能够实现的.java
在support.v7.preference库中做者就用了一种方式实现这种效果:学习
public class PreferenceViewHolder extends RecyclerView.ViewHolder { private final SparseArray<View> mCachedViews = new SparseArray<>(4); public View findViewById(@IdRes int id) { final View cachedView = mCachedViews.get(id); if (cachedView != null) { return cachedView; } else { final View v = itemView.findViewById(id); if (v != null) { mCachedViews.put(id, v); } return v; } } }
这样外部只需经过findViewById
来找到各类各样的控件实例来进行数据绑定便可, 可是声明的ViewHolder却只需一种! 仔细想一想这种经过SparseArray持有的方式其实很是巧妙, 真正将ViewHolder做为各类视图的持有者(Holder)不用再区分类型, 可谓实至名归.设计
稍加改造就能够和新API的findViewById风格彻底保持一致(咱们姑且叫作ItemViewHolder
, 抽象全部列表视图子视图):code
public class ItemViewHolder extends RecyclerView.ViewHolder { private final SparseArrayCompat<View> mCached = new SparseArrayCompat<>(10); public ItemViewHolder(View itemView) { super(itemView); } public <T extends View> T findViewById(@IdRes int resId) { int pos = mCached.indexOfKey(resId); View v; if (pos < 0) { v = itemView.findViewById(resId); mCached.put(resId, v); } else { v = mCached.valueAt(pos); } @SuppressWarnings("unchecked") T t = (T) v; return t; } }
其实RecyclerView.ViewHolder自己就应该设计成这种方式, 而且声明成final
强制移除各类Viewholder类型的强转.get
因此仍是要多看官方成熟的库, 他们的设计和实现都是通过千锤百炼, 对学习很是有益处.it