简体   繁体   English

Android - 可扩展listview的更好替代方案?

[英]Android - Better alternative to expandable listview?

I have a list of items loaded from a web service JSON. 我有一个从Web服务JSON加载的项目列表。 Each of these items has it's own list of sub-items. 这些项目中的每一项都有自己的子项目列表。 Each item has numerous text views. 每个项目都有许多文本视图。 The number of subitems varies dynamically, and consists of multiple textviews. 子项目的数量动态变化,由多个文本视图组成。 There are at times dozens of items with potentially hundreds of subitems. 有时数十个项目可能有数百个子项目。 I want all the information visible all the time, ie I do not actually need the "expandable" part of the expandable listview but it seemed the easiest way to get the children and group layout. 我希望所有信息始终可见,即我实际上并不需要扩展列表视图的“可扩展”部分,但它似乎是获取子项和组布局的最简单方法。

Item1
  sub item 1
  sub item 2

Item 2
  sub item 1
  sub item 2
  sub item 3

etc

I have currently implemented an expandable listview and forced the groups to always be expanded. 我目前已经实现了可扩展的列表视图,并强制组始终进行扩展。 This works, however it is very slow to scroll, not only on the emulator but on my galaxy s2. 这是有效的,但滚动速度非常慢,不仅在模拟器上,而且在我的galaxy s2上。
I am wondering if there is a better way to achieve this? 我想知道是否有更好的方法来实现这一目标?
I considered a single list view and concatenating the strings in the subitems into a single text view but think that this will not be aesthetically pleasing and I won't be able to get the layout I want. 我考虑了一个列表视图,并将子项中的字符串连接成一个文本视图,但认为这不符合美学要求,我将无法获得我想要的布局。
I wondered if there is a way to override the listview adapted so that one of the items is an array itself of other items. 我想知道是否有一种方法来覆盖listview,以便其中一个项目是其他项目的数组本身。 The adapter could iterate over that array and create new textviews on the fly. 适配器可以迭代该数组并动态创建新的文本视图。 I suppose this is what the expandable list view is doing anyway so perhaps this would end up with just as much lag scrolling. 我想这是可扩展列表视图正在做的事情,所以也许这最终会导致延迟滚动。

Any help greatly appreciated 任何帮助非常感谢

You can achieve that with ListView and custom adapter class. 您可以使用ListView和自定义适配器类实现此目的。

Notice that adapter has methods int getViewTypeCount() and int getItemViewType(int position) which you can overwrite. 请注意,适配器具有可以覆盖的方法int getViewTypeCount()int getItemViewType(int position)

look at sample implemation for dataset in Map of lists 查看列表Map中数据集的示例实现

public abstract class ExampleMapAdapter<V extends Map<?, ? extends List<?>>> extends BaseAdapter {

    public static final int VIEW_TYPE_HEADER = 0;
    public static final int VIEW_TYPE_LISTITEM = 1;

    protected V data;
    protected int[] sectionsStart;
    protected Object[] sections;
    protected int count;

    public ExampleMapAdapter(V data) {
        this.data = data;
        onSetData();
    }

    @Override
    public int getCount() {
        return count;
    }

    @Override
    public Object getItem(int position) {
        int sectionIndex = getSectionForPosition(position);
        int innerIndex = position - sectionsStart[sectionIndex];
        if(innerIndex == 0) { //head
            return sections[sectionIndex];
        }
        else { //values
            return data.get(sections[sectionIndex]).get(innerIndex - 1);
        }
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public int getViewTypeCount() {
        return 2;
    }

    @Override
    public int getItemViewType(int position) {
        return Arrays.binarySearch(sectionsStart, position) < 0 ? VIEW_TYPE_LISTITEM : VIEW_TYPE_HEADER;
    }

    public int getPositionForSection(int section) {
        return sectionsStart[section];
    }

    public int getSectionForPosition(int position) {
        int section = Arrays.binarySearch(sectionsStart, position);
        return section < 0 ? -section - 2 : section;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if(getItemViewType(position) == VIEW_TYPE_HEADER) {
            return getHeaderView(position, convertView, parent);
        }
        else {
            return getListItemView(position, convertView, parent);
        }
    }

    @Override
    public void notifyDataSetInvalidated() {
        data = null;
        onSetData();
        super.notifyDataSetInvalidated();
    }

    @Override
    public void notifyDataSetChanged() {
        onSetData();
        super.notifyDataSetChanged();
    }

    protected void onSetData() {
        if(data == null) {
            sectionsStart = null;
            sections = null;
            count = 0;
        }
        else {
            sectionsStart = new int[data.size()];
            sections = data.keySet().toArray(new Object[data.size()]);
            count = 0;
            int i = 0;
            for(List<?> v : data.values()) {
                sectionsStart[i] = count;
                i++;
                count += 1 + v.size();
            }
        }
    }

    protected abstract View getHeaderView(int position, View convertView, ViewGroup parent);

    protected abstract View getListItemView(int position, View convertView, ViewGroup parent);
}

and usage example: 和用法示例:

public class ExampleActivity extends Activity {

    class SubItem {
        public final String text;
        public final int number;
        public final boolean checked;
        public SubItem(String text, int number, boolean checked) {
            this.text = text;
            this.number = number;
            this.checked = checked;
        }
    }

    //use LinkedHashMap or TreeMap as other map implementations may not keep key's order
    final Map<String, List<SubItem>> map = new LinkedHashMap<String, List<SubItem>>();
    {
        List<SubItem> list = new ArrayList<SubItem>();
        list.add(new SubItem("sub item", 1, false));
        list.add(new SubItem("sub item", 2, true));
        map.put("Item1", list);
        list = new ArrayList<SubItem>();
        list.add(new SubItem("sub item", 1, true));
        list.add(new SubItem("sub item", 2, false));
        list.add(new SubItem("sub item", 3, false));
        map.put("Item2", list);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        ListView vList = new ListView(this);
        vList.setAdapter(new ExampleMapAdapter<Map<String, List<SubItem>>>(map) {

            @Override
            protected View getHeaderView(int position, View convertView,
                    ViewGroup parent) {
                TextView v = convertView == null ? 
                        new TextView(parent.getContext()) : (TextView) convertView;
                v.setText((String) getItem(position));
                return v;
            }

            @Override
            protected View getListItemView(int position, View convertView,
                    ViewGroup parent) {
                CheckBox v = convertView == null ? 
                        new CheckBox(parent.getContext()) : (CheckBox) convertView;
                SubItem item = (SubItem) getItem(position);
                v.setText(item.text + " " + item.number);
                v.setChecked(item.checked);
                return v;
            }
        });
        setContentView(vList);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM