簡體   English   中英

創建適配器到CustomView

[英]Creating an Adapter to a CustomView

我一直試圖在網上查找有關如何做到這一點的任何解決方案或示例,但無法找到類似我的問題的任何東西。

我有一個LinearLayout ,我想在ArrayList數據更改時添加/刪除Views

據我所知,唯一的方法是通過擴展AdapterView和使用ArrayAdapter創建一個CustomView

不幸的是,我不理解正確的數據流來解決這個問題。

我在CustomView中指定哪個View是容器? 我可以在實現它的時候在LinearLayout CustomView嗎?

編輯:我強調 - 我不需要ListView 我需要它用於CustomView

您無需在自定義視圖中擴展AdapterView以從適配器生成視圖。 您可以擴展LinearLayout並處理適配器。 最簡單的解決方案如下:

public class CustomAdapterView extends LinearLayout {

    private Adapter adapter;
    private final DataSetObserver observer = new DataSetObserver() {

        @Override
        public void onChanged() {
            refreshViewsFromAdapter();
        }

        @Override
        public void onInvalidated() {
            removeAllViews();
        }
    };

    public CustomAdapterView(Context context) {
        super(context);
    }

    public CustomAdapterView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomAdapterView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public Adapter getAdapter() {
        return adapter;
    }

    public void setAdapter(Adapter adapter) {
        if (this.adapter != null) {
            this.adapter.unregisterDataSetObserver(observer);
        }
        this.adapter = adapter;
        if (this.adapter != null) {
            this.adapter.registerDataSetObserver(observer);
        }
        initViewsFromAdapter();
    }

    protected void initViewsFromAdapter() {
        removeAllViews();
        if (adapter != null) {
            for (int i = 0; i < adapter.getCount(); i++) {
                addView(adapter.getView(i, null, this), i);
            }
        }
    }

    protected void refreshViewsFromAdapter() {
        int childCount = getChildCount();
        int adapterSize = adapter.getCount();
        int reuseCount = Math.min(childCount, adapterSize);

        for (int i = 0; i < reuseCount; i++) {
            adapter.getView(i, getChildAt(i), this);
        }

        if (childCount < adapterSize) {
            for (int i = childCount; i < adapterSize; i++) {
                addView(adapter.getView(i, null, this), i);
            }
        } else if (childCount > adapterSize) {
            removeViews(adapterSize, childCount);
        }
    }
}

由於上面的代碼只是一個簡單的例子,它不處理適配器返回不同類型視圖的情況(例如, Adapter#getViewTypeCount()返回大於1的數字)。

當然,所有定義LinearLayout以添加/刪除視圖的方法都可用,因此它們可能會與您的適配器處理沖突。 您可以通過拋出UnsupportedOperationException來禁用它們:

    @Override
    public void addView(View child) {
        throw new UnsupportedOperationException(
                "You cannot add views directly without adapter!");
    }

(等等所有其他添加/刪除方法),或者通過覆蓋它們來操作適配器的后備數據集(應該強制實現自定義定義的接口,允許在Adapter接口旁邊進行此類修改)。 在這兩種情況下,請記住在代碼中調用來自超類的add remove方法以進行適配器處理。

編輯:擴展LinearLayout的簡單實現,支持Adapter的viewTypesCount:

class CustomAdapterViewTypedImpl extends LinearLayout {

    private Adapter adapter;
    private SparseArray<List<View>> typedViewsCache = new SparseArray<List<View>>();
    private final DataSetObserver observer = new DataSetObserver() {

        @Override
        public void onChanged() {
            refreshViewsFromAdapter();
        }

        @Override
        public void onInvalidated() {
            removeAllViews();
        }
    };

    public CustomAdapterViewTypedImpl(Context context) {
        super(context);
    }

    public CustomAdapterViewTypedImpl(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomAdapterViewTypedImpl(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public Adapter getAdapter() {
        return adapter;
    }

    public void setAdapter(Adapter adapter) {
        if (this.adapter != null) {
            this.adapter.unregisterDataSetObserver(observer);
        }
        this.adapter = adapter;
        if (this.adapter != null) {
            this.adapter.registerDataSetObserver(observer);
        }
        initViewsFromAdapter();
    }

    protected void initViewsFromAdapter() {
        typedViewsCache.clear();
        removeAllViews();
        View view;
        if (adapter != null) {
            for (int i = 0; i < adapter.getCount(); i++) {
                view = adapter.getView(i, null, this);
                addToTypesMap(adapter.getItemViewType(i), view, typedViewsCache);
                addView(view, i);
            }
        }
    }

    protected void refreshViewsFromAdapter() {
        SparseArray<List<View>> typedViewsCacheCopy = typedViewsCache;
        typedViewsCache = new SparseArray<List<View>>();
        removeAllViews();
        View convertView;
        int type;
        for (int i = 0; i < adapter.getCount(); i++) {
            type = adapter.getItemViewType(i);
            convertView = shiftCachedViewOfType(type, typedViewsCacheCopy);
            convertView = adapter.getView(i, convertView, this);
            addToTypesMap(type, convertView, typedViewsCache);
            addView(convertView, i);
        }
    }

    private static void addToTypesMap(int type, View view, SparseArray<List<View>> typedViewsCache) {
        List<View> singleTypeViews = typedViewsCache.get(type);
        if(singleTypeViews == null) {
            singleTypeViews = new ArrayList<View>();
            typedViewsCache.put(type, singleTypeViews);
        }
        singleTypeViews.add(view);
    }

    private static View shiftCachedViewOfType(int type, SparseArray<List<View>> typedViewsCache) {
        List<View> singleTypeViews = typedViewsCache.get(type);
        if(singleTypeViews != null) {
            if(singleTypeViews.size() > 0) {
                return singleTypeViews.remove(0);
            }
        }
        return null;
    }
}

看看AdapterView實現。 為您主要擴展DataSetobserver 794行。

只是為了給你一個粗略的想法,
1)在Custom View類中創建擴展DataSetObserver的類。

2)從自定義視圖聲明自己的界面,以獲取視圖/數據詳細信息,並讓CustomAdapter實現它。

3)每當您的自定義中的數組調用onChanged()/ onInvalidated()時,您的自定義中的DatSetObserver發生更改。

如果您對AdapterView非常認真,請點擊此鏈接

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM