カスタム ビューのアダプタからビューを生成するために 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 メソッドを呼び出すことを忘れないでください。
編集:アダプタのviewTypesCountをサポートするLinearLayoutを拡張する簡単な実装:
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;
}
}