咱們知道在通常的列表視圖(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