Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>You do not need to extend AdapterView to generate your views from adapter in your custom view. You can extend <code>LinearLayout</code> and handle adapter. The simplest solution would look like:</p> <pre><code>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 &lt; 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 &lt; reuseCount; i++) { adapter.getView(i, getChildAt(i), this); } if (childCount &lt; adapterSize) { for (int i = childCount; i &lt; adapterSize; i++) { addView(adapter.getView(i, null, this), i); } } else if (childCount &gt; adapterSize) { removeViews(adapterSize, childCount); } } } </code></pre> <p>As the code above is only a simple example it does not handle situation where adapter returns views of different types (e.g. <code>Adapter#getViewTypeCount()</code> returns number greater than 1).</p> <p>Of course all methods defined LinearLayout for adding/removing views are available so they may collide with your adapter handling. You could disable them by throwing UnsupportedOperationException:</p> <pre><code> @Override public void addView(View child) { throw new UnsupportedOperationException( "You cannot add views directly without adapter!"); } </code></pre> <p>(and so on for all other add/remove methods), or by overriding them to manipulate adapter's backing dataset (which should be forced to implement your custom defined interface allowing such modifications next to Adapter interface). In both cases remember to call add remove methods from superclass in your code for adapter handling.</p> <p>EDIT: And simple implementation extending LinearLayout with support for Adapter's viewTypesCount:</p> <pre><code>class CustomAdapterViewTypedImpl extends LinearLayout { private Adapter adapter; private SparseArray&lt;List&lt;View&gt;&gt; typedViewsCache = new SparseArray&lt;List&lt;View&gt;&gt;(); 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 &lt; adapter.getCount(); i++) { view = adapter.getView(i, null, this); addToTypesMap(adapter.getItemViewType(i), view, typedViewsCache); addView(view, i); } } } protected void refreshViewsFromAdapter() { SparseArray&lt;List&lt;View&gt;&gt; typedViewsCacheCopy = typedViewsCache; typedViewsCache = new SparseArray&lt;List&lt;View&gt;&gt;(); removeAllViews(); View convertView; int type; for (int i = 0; i &lt; 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&lt;List&lt;View&gt;&gt; typedViewsCache) { List&lt;View&gt; singleTypeViews = typedViewsCache.get(type); if(singleTypeViews == null) { singleTypeViews = new ArrayList&lt;View&gt;(); typedViewsCache.put(type, singleTypeViews); } singleTypeViews.add(view); } private static View shiftCachedViewOfType(int type, SparseArray&lt;List&lt;View&gt;&gt; typedViewsCache) { List&lt;View&gt; singleTypeViews = typedViewsCache.get(type); if(singleTypeViews != null) { if(singleTypeViews.size() &gt; 0) { return singleTypeViews.remove(0); } } return null; } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload