Android ExpandableListView with Checkbox, Controlling checked state

前端 未结 4 1730
温柔的废话
温柔的废话 2020-12-03 18:07

Friends,

I am trying to write a application which use checkbox in ExpandableListView, I got a problem here which is maintaining checkbox state of the application, I

相关标签:
4条回答
  • 2020-12-03 18:45

    I also have this problem. Finally I found the root cause and the solution. To fix this, instead of setting the checkState for the checkBox, you should set its containing listView's checkState.

        public class MyExpandableListViewAdapter extends BaseExpandableListAdapter {
     ....
    
        private boolean[][] checkedState;
    
        private void prepareData() {
              checkedState =new boolean[itemData.length][]; 
    
              for (int i=0; i<itemData.length; i++) {
                  groupData.append(i, String.format("Group %d", i));
                  checkedState[i] = new boolean[itemData[i].length];
                  Arrays.fill(checkedState[i],false);
              }
        }
    
        @Override
        public View getChildView(final int groupPosition, final int childPosition,boolean isLastChild, View convertView, ViewGroup parent) {
            View itemView = convertView;
            final ViewHolder vh;
            if (itemView == null) {
               LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
               itemView = inflater.inflate(R.layout.item_view, null);
               vh = new ViewHolder();
               vh.layout = (CheckableLinearLayout)itemView.findViewById(R.id.layout);
               itemView.setTag(vh);
            } else {
               vh = (ViewHolder)itemView.getTag();
            }
    
            final ExpandableListView listView = ((ExpandableListView)((MainActivity)context).findViewById(R.id.list));
            final int position = listView.getFlatListPosition(ExpandableListView.getPackedPositionForChild(groupPosition, childPosition));
            listView.setItemChecked(position, checkedState[groupPosition][childPosition]);
    
            vh.layout.setOnClickListener(new OnClickListener() {
    
            @Override
            public void onClick(View v) {
            ((CheckableLinearLayout)v).toggle();
                checkedState[groupPosition][childPosition] = !checkedState[groupPosition][childPosition]; 
                listView.setItemChecked(position, ((CheckableLinearLayout)v).isChecked());
             }
         });
         return itemView;
      }
      ...
    }
    
    0 讨论(0)
  • 2020-12-03 18:45

    Expandable ListView With Checkbox.

    We can get the complete example in github which is maintaining the checkbox state of the expandable list.

    Click the link to get Android studio project
    https://github.com/bhat-dinesh/ExpandableListViewWithCheckBox

    I hope this helps :)

    0 讨论(0)
  • 2020-12-03 18:46

    this is my answer to the this issue, u need to keep a check state for individual child and check on it when the the child is clicked. after some research, this is due to android's view lifecycle causing the view to refresh thus not keeping the state.

    public class MyExpandableListAdapter extends BaseExpandableListAdapter {
    //Variables
    // Sample data set.  children[i] contains the children (String[]) for groups[i].
    private String[] groups = { "People Names", "Dog Names", "Cat Names", "Fish Names" }; //headers
    private String[][] children = {
            { "Arnold", "Barry", "Chuck", "David" },
            { "Ace", "Bandit", "Cha-Cha", "Deuce" },
            { "Fluffy", "Snuggles" },
            { "Goldy", "Bubbles" }
    };
    private String[] group_vaues = {"PN", "DN", "CN", "FN"};
    private String[][] children_values = {
            { "Ar", "Ba", "Ch", "Da" },
            { "Ace", "Ban", "Cha", "Deu" },
            { "Flu", "Snu" },
            { "Gol", "Bub" }
    };
    ArrayList<ArrayList<Integer>> check_states = new ArrayList<ArrayList<Integer>>();
    
    private Context context;
    
    //Constructors
    public MyExpandableListAdapter() {
    
    }
    
    public MyExpandableListAdapter(Context c) {
        this.context = c;
    }
    
    //Set Methods
    public void setGroupsAndValues(String[] g, String[] v) {
        this.groups = g;
        this.group_vaues = v;
    }
    
    public void setChildrenAndValues(String[][] c, String[][] v) {
        this.children = c;
        this.children_values = v;
        //initialize the states to all 0;
        for(int i = 0; i < c.length; i++) {
            ArrayList<Integer> tmp = new ArrayList<Integer>();
            for(int j = 0; j < c[i].length; j++) {
                tmp.add(0);
            }
            check_states.add(tmp);
        }
    }
    
    //Get Methods
    public Object getChild(int groupPosition, int childPosition) {
        return children[groupPosition][childPosition];
    }
    
    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }
    
    public int getChildrenCount(int groupPosition) {
        return children[groupPosition].length;
    }
    
    public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
            View convertView, ViewGroup parent) {
        View grid;
    
    
       LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
       grid = inflater.inflate(R.layout.specialty_list_item, parent, false);
    
       final int grpPos = groupPosition;
       final int childPos = childPosition;
    
        TextView header = (TextView)grid.findViewById(R.id.title);
        header.setText(getChild(groupPosition, childPosition).toString());
        final View tick = grid.findViewById(R.id.image);
        if(check_states.get(grpPos).get(childPos) == 1)
            tick.setVisibility(View.VISIBLE);
        else
            tick.setVisibility(View.GONE);
    
        grid.setOnClickListener(new OnClickListener(){
            @Override
            public void onClick(View v) {
                check_states.get(grpPos).set(childPos, 1);
                tick.setVisibility(View.VISIBLE);
            }
        });
    
        return grid;
    }
    
    public Object getGroup(int groupPosition) {
        return groups[groupPosition];
    }
    
    public int getGroupCount() {
        return groups.length;
    }
    
    public long getGroupId(int groupPosition) {
        return groupPosition;
    }
    
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
            ViewGroup parent) {
        View grid;
    
        if(convertView==null){
           grid = new View(context);
           LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
           grid = inflater.inflate(R.layout.specialty_header, parent, false);
        }else{
           grid = (View)convertView;
        }
    
        TextView header = (TextView)grid.findViewById(R.id.specialty_header);
        header.setText(getGroup(groupPosition).toString());
    
    
        return grid;
    }
    
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return true;
    }
    
    public boolean hasStableIds() {
        return true;
    }
    

    }

    0 讨论(0)
  • 2020-12-03 18:52

    ExpandableListView with multiselect. Tested on API 4.3 and 4.0.3 This code also correctly handles changing screen orientation. Blocking groups made ​​to work properly with the selected elements through SparseBooleanArray.

    I hope this sample code will help :)

    Activity

    ExpandableListView list;
    ArrayList<YouCat> cat = new ArrayList<YouCat>();
    private YourAdapter mAdapter;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout);
        list = (ExpandableListView)findViewById(R.id.list);
        mAdapter = new YourAdapter(this, list, cat);
        if(savedInstanceState == null)
            //collect your data
        list.setAdapter(mAdapter);
        list.setItemsCanFocus(false);
        list.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE);
        list.setOnChildClickListener(this);
        list.setOnGroupClickListener(this);
    }
    
    public boolean onGroupClick(ExpandableListView parent, View v,
                int groupPosition, long id) {
            return cat.get(groupPosition).selected;
    }
    
    public boolean onChildClick(ExpandableListView parent, View v,
                int groupPosition, int childPosition, long id) {
            YouCat cat = new YouCat();
            YouSubCat subcat = new YouSubCat();
            subcat = cat.get(groupPosition).sub.get(childPosition);
            subcat.selected = !cat.get(groupPosition).sub.get(childPosition).selected;
            cat.get(groupPosition).sub.set(childPosition, subcat);
    
            boolean isGroupHasSelected = false;
            for(int i = 0; i < cat.get(groupPosition).sub.size() && !isGroupHasSelected; i ++){
                isGroupHasSelected = cat.get(groupPosition).sub.get(i).selected;
            }
            cat = cat.get(groupPosition);
            cat.selected = isGroupHasSelected;
            cat.set(groupPosition, cat);
            //mAdapter.notifyDataSetChanged();
    
            int position = parent.getFlatListPosition(ExpandableListView.getPackedPositionForChild(groupPosition, childPosition));
            parent.setItemChecked(position, subcat.selected);
    
            return true;
    }
    
     public void onRestoreInstanceState(Bundle savedInstanceState) {
         super.onRestoreInstanceState(savedInstanceState);
         //restore data 
         cat = (ArrayList<YouCat>) savedInstanceState.getSerializable("cat");
         Type selType = new TypeToken<SparseBooleanArray>() {}.getType();
         SparseBooleanArray checked = new Gson().fromJson(savedInstanceState.getString("sel"), selType);
         //set new data to adapter and refresh
         mAdapter.refreshList(cat);
     }
    
    
     public void onSaveInstanceState(Bundle savedInstanceState) {
         super.onSaveInstanceState(savedInstanceState);
         //save data and selection from list to bundle
         savedInstanceState.putSerializable("cat", cat);
         savedInstanceState.putString("sel", new Gson().toJson(list.getCheckedItemPositions()).toString());
     }
    

    Adapter

    public class YouAdapter extends BaseExpandableListAdapter{
    
        private Context context;
        private List<YouCat> mGroupCollection;
        private ExpandableListView mExpandableListView;
    
        public YouAdapter(Context context, ExpandableListView pExpandableListView,
                List<YouCat> pGroupCollection) {
            this.context = context;
            this.mGroupCollection = pGroupCollection;
            this.mExpandableListView = pExpandableListView;
        }
    
        @Override
        public Object getChild(int groupPosition, int childPosition) {
            return mGroupCollection.get(groupPosition).sub.get(childPosition).name;
        }
    
        @Override
        public long getChildId(int groupPosition, int childPosition) {
            return childPosition;
        }
    
        class ChildHolder {
        CheckBox checkBox;
        TextView name, desc;
       }
    
        @Override
        public View getChildView(int groupPosition, int childPosition,
                boolean isLastChild, View convertView, ViewGroup parent) {
            ChildHolder childHolder;
            if( convertView == null ){
                convertView = LayoutInflater.from(context).inflate(R.layout.childrow, null);
                childHolder = new ChildHolder();
                childHolder.checkBox = (CheckBox) convertView.findViewById(R.id.myCheckBox);
                childHolder.name=(TextView)convertView.findViewById(R.id.textView1);
                childHolder.desc=(TextView)convertView.findViewById(R.id.textView2);
                convertView.setTag(childHolder);
           }else{
                childHolder = (ChildHolder) convertView.getTag(); 
           }
            childHolder.name.setText(mGroupCollection.get(groupPosition).sub.get(childPosition).name);
            childHolder.desc.setText(mGroupCollection.get(groupPosition).sub.get(childPosition).desc);
            childHolder.checkBox.setChecked(mGroupCollection.get(groupPosition).sub.get(childPosition).selected);
    
            return convertView;
        }
    
        @Override
        public int getChildrenCount(int groupPosition) {
            return mGroupCollection.get(groupPosition).sub.size();
        }
    
        @Override
        public Object getGroup(int groupPosition) {
            return mGroupCollection.get(groupPosition);
        }
    
        @Override
        public int getGroupCount() {
            return mGroupCollection.size();
        }
    
        @Override
        public long getGroupId(int groupPosition) {
            return groupPosition;
        }
    
        class GroupHolder {
          TextView title;
       }
    
        @Override
        public View getGroupView(int groupPosition, boolean isExpanded,
                View convertView, ViewGroup parent) {
            GroupHolder groupHolder;
           if( convertView == null ){
                convertView = LayoutInflater.from(context).inflate(R.layout.grouplayout,null);
                groupHolder = new GroupHolder();
                groupHolder.title = (TextView)convertView.findViewById( R.id.text1 );
                convertView.setTag(groupHolder);
           }else{
                groupHolder = (GroupHolder) convertView.getTag(); 
           }
           groupHolder.title.setText(mGroupCollection.get(groupPosition).name);
           return convertView;
        }
    
        @Override
        public boolean hasStableIds() {
            return true;
        }
    
        @Override
        public boolean isChildSelectable(int groupPosition, int childPosition) {
            return true;
        }
    
        public void refreshList(List<YouCat> collection){
            mGroupCollection = collection;
            notifyDataSetChanged();
            for(int g = 0; g < mGroupCollection.size(); g ++){
                if(mGroupCollection.get(g).selected)
                    mExpandableListView.expandGroup(g);
                else
                    mExpandableListView.collapseGroup(g);
            }
        }
    
    }
    

    YouCat class

    public class YouCat implements Serializable {
            private static final long serialVersionUID = 2070450081971040619L;
            public String name = null;
            public boolean selected = false;
            public ArrayList<YouSubCat> sub = new ArrayList<YouSubCat>();
    }
    

    YouSubCat class

    public class YouSubCat implements Serializable {
        private static final long serialVersionUID = -1487507723105914936L;
        public String name = null, desc = null;
        public boolean selected = false;
    }
    

    Child row layout

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >
    
        <CheckBox
            android:id="@+id/myCheckBox"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:clickable="false"
            android:focusable="false" />
    
        <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_alignParentTop="true"
            android:layout_marginLeft="10dp"
            android:layout_toRightOf="@+id/myCheckBox"
            android:text="TextView"
            android:textAppearance="?android:attr/textAppearanceLarge" />
    
        <TextView
            android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignLeft="@+id/textView1"
            android:layout_alignParentRight="true"
            android:layout_below="@+id/textView1"
            android:text="TextView" />
    
    </RelativeLayout>
    

    Group layout

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="8dp" >
    
        <TextView
            android:id="@+id/text1"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:paddingLeft="?android:attr/expandableListPreferredItemPaddingLeft"
            android:textAppearance="?android:attr/textAppearanceMedium" />
    
    </LinearLayout>
    

    Get selected child items

    final SparseBooleanArray checkedItems = list.getCheckedItemPositions();
    for (int i = 0; i < checkedItems.size(); i++) {
      if(checkedItems.valueAt(i))
        data = ((String)list.getItemAtPosition(checkedItems.keyAt(i)));
    }
    
    0 讨论(0)
提交回复
热议问题