一勞永逸——RecyclerView無類型強轉的通用ViewHolder

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

相關文章
相關標籤/搜索