Issue with Expanding Multi-Level ExpandableListView

前端 未结 2 413
暗喜
暗喜 2020-12-05 20:59

I have a multi level (3 levels, Root -> Parent -> Child) ExpandableListView containing children that are also ExpandableListViews. I\'m having no issue filling them up; howe

相关标签:
2条回答
  • 2020-12-05 21:26

    This is the best example I have found and used also: http://androidcodesnips.blogspot.in/2011/09/three-level-expandable-list.html

    Its working, I have changed it as my need.

    tags: 3 level expandablelistview, multi level listview

    0 讨论(0)
  • 2020-12-05 21:31

    I ended up using a multi level ExpandableListView adapter from another post in stackoverflow. Unfortunately I just can't find the link anymore so I'll just post my code here.

    Top Level of the ExpandableListView adapter.

    RootAdapter.java:

    public class RootAdapter extends BaseExpandableListAdapter {
    
        private Object root;
    
        private final LayoutInflater inflater;
    
        public class Entry {
            public final CustExpListview cls;
            public final SecondLevelAdapter sadpt;
    
            public Entry(CustExpListview cls, SecondLevelAdapter sadpt) {
                this.cls = cls;
                this.sadpt = sadpt;
            }
        }
    
        public Entry[] lsfirst;
    
        // you can change the constructor depending on which listeners you wan't to use.
        public RootAdapter(Context context, Object root, ExpandableListView.OnGroupClickListener grpLst,
            ExpandableListView.OnChildClickListener childLst, ExpandableListView.OnGroupExpandListener grpExpLst) {
            this.root = root;
            this.inflater = LayoutInflater.from(context);
    
            lsfirst = new Entry[root.children.size()];
    
            for (int i = 0; i < root.children.size(); i++) {
                final CustExpListview celv = new CustExpListview(context);
                SecondLevelAdapter adp = new SecondLevelAdapter(root.children.get(i));
                celv.setAdapter(adp);
                celv.setGroupIndicator(null);
                celv.setOnChildClickListener(childLst);
                celv.setOnGroupClickListener(grpLst);
                celv.setOnGroupExpandListener(grpExpLst);
    
                lsfirst[i] = new Entry(celv, adp);
            }
    
        }
    
        @Override
        public Object getChild(int groupPosition, int childPosition) {
            return childPosition;
        }
    
        @Override
        public long getChildId(int groupPosition, int childPosition) {
            return childPosition;
        }
    
        @Override
        public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
            View convertView, ViewGroup parent) {
            // second level list
            return lsfirst[groupPosition].cls;
        }
    
        @Override
        public int getChildrenCount(int groupPosition) {
            return 1;
        }
    
        @Override
        public Object getGroup(int groupPosition) {
            return root.children.get(groupPosition);
        }
    
        @Override
        public int getGroupCount() {
            return root.children.size();
        }
    
        @Override
        public long getGroupId(int groupPosition) {
            return groupPosition;
        }
    
        @Override
        public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
            ViewGroup parent) {
    
            // first level
    
            View layout = convertView;
            GroupViewHolder holder;
            final Object item = (Object) getGroup(groupPosition);
    
            if (layout == null) {
                layout = inflater.inflate(R.layout.item_root, parent, false);
                holder = new GroupViewHolder();
                holder.title = (TextView) layout.findViewById(R.id.itemRootTitle);
                layout.setTag(holder);
            } else {
                holder = (GroupViewHolder) layout.getTag();
            }
    
            holder.title.setText(item.title.trim());
    
            return layout;
        }
    
        private static class GroupViewHolder {
            TextView title;
        }
    
        @Override
        public boolean hasStableIds() {
            return true;
        }
    
        @Override
        public boolean isChildSelectable(int groupPosition, int childPosition) {
            return true;
        }
    }
    

    Custom ExpandableListView with the solution to items sometimes not being displayed. There is also a workaround to a known bug for IllegalArgumentException being called when destroying the view (by pressing the back button essentially).

    CustExpListview.java:

    public class CustExpListview extends ExpandableListView {
    
        public CustExpListview(Context context) {
            super(context);
    
        }
    
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            // the value (2000) should not be fixed and be calculated
            // as follows: cell_height x root_items_count x root_items_children_count
            heightMeasureSpec = MeasureSpec.makeMeasureSpec(2000, MeasureSpec.AT_MOST);
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    
        @Override
        protected void onDetachedFromWindow() {
            try {
                super.onDetachedFromWindow();
            } catch (IllegalArgumentException e) {
                // TODO: Workaround for http://code.google.com/p/android/issues/detail?id=22751
            }
        }
    }
    

    Finally, the code to the last level adapter.

    public class SecondLevelAdapter extends BaseExpandableListAdapter {
    
        public Object child;
    
        public SecondLevelAdapter(Object child) {
            this.child = child;
        }
    
        @Override
        public Object getChild(int groupPosition, int childPosition) {
            return child.children.get(groupPosition).children.get(childPosition);
        }
    
        @Override
        public long getChildId(int groupPosition, int childPosition) {
            return childPosition;
        }
    
        // third level
        @Override
        public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
                View convertView, ViewGroup parent) {
            View layout = convertView;
            final Object item = (Object) getChild(groupPosition, childPosition);
    
            ChildViewHolder holder;
    
            if (layout == null) {
                layout = inflater.inflate(R.layout.item_child, parent, false);
    
                holder = new ChildViewHolder();
                holder.title = (TextView) layout.findViewById(R.id.itemChildTitle);
                layout.setTag(holder);
            } else {
                holder = (ChildViewHolder) layout.getTag();
            }
    
            holder.title.setText(item.title.trim());
    
            return layout;
        }
    
        @Override
        public int getChildrenCount(int groupPosition) {
            return child.children.get(groupPosition).children.size();
        }
    
        @Override
        public Object getGroup(int groupPosition) {
            return child.children.get(groupPosition);
        }
    
        @Override
        public int getGroupCount() {
            return child.children.size();
        }
    
        @Override
        public long getGroupId(int groupPosition) {
            return groupPosition;
        }
    
        // Second level
        @Override
        public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
                ViewGroup parent) {
            View layout = convertView;
            ViewHolder holder;
    
            final Object item = (Object) getGroup(groupPosition);
    
            if (layout == null) {
                layout = inflater.inflate(R.layout.item_parent, parent, false);
                holder = new ViewHolder();
                holder.title = (TextView) layout.findViewById(R.id.itemParentTitle);
                layout.setTag(holder);
            } else {
                holder = (ViewHolder) layout.getTag();
            }
    
            holder.title.setText(item.title.trim());
    
            return layout;
        }
    
        @Override
        public void registerDataSetObserver(DataSetObserver observer) {
            super.registerDataSetObserver(observer);
        }
    
        @Override
        public void unregisterDataSetObserver(DataSetObserver observer) {
            Log.d("SecondLevelAdapter", "Unregistering observer");
            if (observer != null) {
                super.unregisterDataSetObserver(observer);
            }
        }
    
        @Override
        public boolean hasStableIds() {
            return true;
        }
    
        @Override
        public boolean isChildSelectable(int groupPosition, int childPosition) {
            return true;
        }
    
        private static class ViewHolder {
            TextView title;
        }
    
        private static class ChildViewHolder {
            TextView title;
        }
    
    }
    

    I hope this helps!!!

    Update

    This is an example of how I call the above adapter.

    MainActivity:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        final List<Object> objects = yourItems;
        if (!objects.isEmpty()) {
            final ExpandableListView elv = (ExpandableListView) findViewById(R.id.yourExpandableListView);
            /* Item click listeners below */
    
            // First level items in the ExpandableListView
            elv.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
                @Override
                public boolean onGroupClick(ExpandableListView eListView, View view, int groupPosition,
                        long id) {
                    // TODO: whatever you need
                    return false /* or true depending on what you need */;
                }
            });
    
            // Second level items in the ExpandableListView
            ExpandableListView.OnGroupClickListener grpLst = new ExpandableListView.OnGroupClickListener() {
                @Override
                public boolean onGroupClick(ExpandableListView eListView, View view, int groupPosition,
                        long id) {
                    // TODO: whatever you need
                    return false /* or true depending on what you need */;
                }
            };
    
            // Third (and last) level items in the ExpandableListView
            ExpandableListView.OnChildClickListener childLst = new ExpandableListView.OnChildClickListener() {
                @Override
                public boolean onChildClick(ExpandableListView eListView, View view, int groupPosition,
                        int childPosition, long id) {
                    // TODO: whatever you need
                    return false /* or true depending on what you need */;
                }
            };
    
            ExpandableListView.OnGroupExpandListener grpExpLst = new ExpandableListView.OnGroupExpandListener() {
                @Override
                public void onGroupExpand(int groupPosition) {
                    /* this one is not required of course, you can delete it from the RootAdapter Constructor
                     * it is just an example as to how to implement Listeners on the second level items */
                }
            };
    
            final RootAdapter adapter = new RootAdapter(this, objects, grpLst, childLst, grpExpLst);
            elv.setAdapter(adapter);
        }
    }
    

    This is how my class Object would look like.

    Object.java:

    public class Object {
        public String title; // use getters and setters instead
        public List<Object> children; // same as above
    
        public Object() {
            children = new ArrayList<Object>();
        }
    }
    
    0 讨论(0)
提交回复
热议问题