0

I have a ListView where I want to display items from more than one adapters, for example two SimpleCursorAdapters that come from different queries. Each adapter has its own layout, which don't have to be the same.

I tried with the following wrapper class:

public class MultiListAdapter implements ListAdapter {

    private List<ListAdapter> adapters;

    private static class PositionResult {
        ListAdapter adapter;
        int position;
        PositionResult(ListAdapter adapter, int position) {
            this.adapter = adapter;
            this.position = position;
        }
    }

    private PositionResult getInternalPosition(int position) {
        int i = 0;
        int result = position;
        for (ListAdapter adapter: adapters) {
            int count = adapter.getCount();
            if (result < count) {
                return new PositionResult(adapter, result);
            }
            result -= count;
            ++i;
        }
        return null;
    }

    public MultiListAdapter(List<ListAdapter> adapters) {
        this.adapters = adapters;
    }

    @Override
    public int getCount() {
        int result = 0;
        int i = 0;
        for (ListAdapter adapter: adapters) {
            int c = adapter.getCount();
            result += c;
        }
        return result;
    }

    @Override
    public Object getItem(int position) {
        PositionResult p = getInternalPosition(position);
        return p.adapter.getItem(p.position);
    }

    @Override
    public long getItemId(int position) {
        PositionResult p = getInternalPosition(position);
        return p.adapter.getItemId(p.position);
    }

    @Override
    public int getItemViewType(int position) {
        PositionResult p = getInternalPosition(position);
        return p.adapter.getItemViewType(p.position);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        PositionResult p = getInternalPosition(position);
        return p.adapter.getView(p.position, convertView, parent);
    }

    @Override
    public int getViewTypeCount() {
        int result = 0;
        for (ListAdapter adapter: adapters) {
            result += adapter.getViewTypeCount();
        }
        return result;
    }

    @Override
    public boolean hasStableIds() {
        for (ListAdapter adapter: adapters) {
            if (!adapter.hasStableIds()) {
                return false;
            }
        }
        return true;
    }

    @Override
    public boolean isEmpty() {
        for (ListAdapter adapter: adapters) {
            if (!adapter.isEmpty()) {
                return false;
            }
        }
        return true;
    }

    @Override
    public void registerDataSetObserver(DataSetObserver observer) {
        for (ListAdapter adapter: adapters) {
            adapter.registerDataSetObserver(observer);
        }

    }

    @Override
    public void unregisterDataSetObserver(DataSetObserver observer) {
        for (ListAdapter adapter: adapters) {
            adapter.unregisterDataSetObserver(observer);
        }
    }

    @Override
    public boolean areAllItemsEnabled() {
        for (ListAdapter adapter: adapters) {
            if (!adapter.areAllItemsEnabled()) {
                return false;
            }
        }
        return true;
    }

    @Override
    public boolean isEnabled(int position) {
        PositionResult p = getInternalPosition(position);
        return p.adapter.isEnabled(p.position);
    }

}

This works if I only have a few elements in each list. But if it has more, and I need to scroll, then the list breaks completely, displays the elements mixed up, and when I click on them, they even give me different positions than their real position.

What's wrong with the code above?

4

1 に答える 1

1

問題はgetItemViewType()、実際のビュー タイプが異なるにもかかわらず、メソッドが異なるビューに対して同じ値を返すことです。これにより、システムは異なるタイプのビューを再利用しようとします。

そのメソッドは、代わりに次のようになります。

private int getMaxViewType() {
    int result = 1;
    for (ListAdapter adapter: adapters) {
        result = Math.max(result, adapter.getViewTypeCount());
    }
    return result;
}

@Override
public int getItemViewType(int position) {
    PositionResult p = getInternalPosition(position);
    return p.adapterId*getMaxViewType() + p.adapter.getItemViewType(p.position);
}
于 2012-09-13T12:57:08.397 に答える