【问题标题】:Creating an Adapter to a CustomView为 CustomView 创建适配器
【发布时间】:2013-01-27 17:55:23
【问题描述】:

我一直试图在网上寻找有关如何做到这一点的任何解决方案或示例,但无法找到与我的问题相似的任何东西。

我有一个LinearLayout,我想在ArrayList 数据更改时添加/删除Views

据我了解,唯一的方法是通过扩展AdapterView 并使用ArrayAdapter 创建CustomView

很遗憾,我不了解解决此问题的正确数据流。

我在CustomView 的哪里指定哪个 View 是容器? 我可以在实现它时将CustomView 投射到LinearLayout 上吗?

编辑: 我强调 - 我不需要ListView。我需要CustomView

【问题讨论】:

    标签: java android adapter


    【解决方案1】:

    您无需扩展 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!");
        }
    

    (对于所有其他添加/删除方法等等),或者通过覆盖它们来操作适配器的支持数据集(应该强制实现您自定义的接口,允许在适配器接口旁边进行此类修改)。在这两种情况下,请记住在您的代码中从超类调用 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;
        }
    }
    

    【讨论】:

      【解决方案2】:

      查看AdapterView 的实现。对你来说,它主要是扩展 DataSetobserver 第 794 行。

      只是给你一个粗略的想法,
      1) 在自定义视图类中创建扩展 DataSetObserver 的类。

      2) 从您的自定义视图中声明您自己的接口以获取视图/数据详细信息,并让您的 CustomAdapter 实现它。

      3) 每当您的自定义中的 DatSetObserver 的 Array 调用 onChanged()/onInvalidated() 发生变化时。

      如果您对 AdapterView 非常认真,请关注 this link

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-14
        • 2017-09-12
        • 2021-12-12
        • 2013-07-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多