【问题标题】:Android ExpandableListView with Checkbox, Controlling checked stateAndroid ExpandableListView 带复选框,控制选中状态
【发布时间】:2011-07-01 10:03:35
【问题描述】:

朋友们,

我正在尝试编写一个在 ExpandableListView 中使用复选框的应用程序,我在这里遇到了一个问题,即维护应用程序的复选框状态,我从 here 获得了示例,我的问题是维护复选框的选中状态,无论何时我选中其中一个复选框并展开列表,复选框没有它们应该具有的选中状态。我试图通过添加 ArrayList 来存储商店的位置并重新加载 getChildView() 中的位置,但仍然无法实现我想要做的事情。这是我的代码

public class ElistCBox extends ExpandableListActivity {

    private static final String LOG_TAG = "ElistCBox";
    ArrayList<String > chkState = new ArrayList<String>();
    static final String colors[] = {"grey","blue","yellow","red"};
    static final String shades[][] ={ { "lightgrey","#D3D3D3","dimgray","#696969", "sgi >gray 92","#EAEAEA"},
        { "dodgerblue 2","#1C86EE","steelblue >2","#5CACEE","powderblue","#B0E0E6"},
        { "yellow 1","#FFFF00", "gold 1","#FFD700","darkgoldenrod 1"," #FFB90F" },
        {"indianred 1","#FF6A6A", "firebrick 1","#FF3030", "maroon","#800000" } };

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle icicle)
    {
        super.onCreate(icicle);
        setContentView(R.layout.main); 
        SimpleExpandableListAdapter expListAdapter = new SimpleExpandableListAdapter( 
            this,
            createGroupList(),
            R.layout.group_row, new String[] { "colorName" },
            new int[] { R.id.childname }, createChildList(),
            R.layout.child_row,
            new String[] { "shadeName", "rgb" },
            new int[] { R.id.childname, R.id.rgb }
        ) { 
            @Override public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent)
            {
                final View v = super.getChildView(groupPosition, childPosition, isLastChild, convertView, parent);

                final CheckBox chkColor = (CheckBox)v.findViewById(R.id.check1);

                if(chkState.contains(groupPosition+","+childPosition)){
                    chkColor.setChecked(true);
                }else{
                    chkColor.setChecked(false);
                }
                chkColor.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Log.e("Checkbox Onclick Listener", Integer.toString(groupPosition) + " - " + Integer.toString(childPosition));
                    }
                });
                chkColor.setOnCheckedChangeListener(new OnCheckedChangeListener() {
                    @Override
                    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                        Log.e("Checkbox check change Listener", Integer.toString(groupPosition) + " - " + Integer.toString(childPosition));
                        if(chkColor.isChecked()){
                            chkState.add(groupPosition+","+childPosition);
                        } else {
                            chkState.remove(groupPosition+","+childPosition); 
                        }
                    }
                });
                return super.getChildView(groupPosition, childPosition, isLastChild, convertView, parent);
            }
        };
        setListAdapter( expListAdapter );
    }

    public void onContentChanged  () {
        super.onContentChanged();
        Log.e( LOG_TAG, "onContentChanged" );
    }

    public boolean onChildClick(
            ExpandableListView parent, 
            View v, 
            int groupPosition,
            int childPosition,
            long id) {
        Log.e( LOG_TAG, "onChildClick: "+childPosition );
        CheckBox cb = (CheckBox)v.findViewById( R.id.check1 );
        if( cb != null )
        cb.toggle();
        return false;
    }

    public void  onGroupExpand  (int groupPosition) {
        Log.e( LOG_TAG,"onGroupExpand: "+groupPosition );
    }

    private List createGroupList() {
        ArrayList result = new ArrayList();
        for( int i = 0 ; i < colors.length ; ++i ) {
            HashMap m = new HashMap();
            m.put( "colorName",colors[i] );
            result.add( m );
        }
        return (List)result; 
    }

    private List createChildList() {
        ArrayList result = new ArrayList();
        for( int i = 0 ; i < shades.length ; ++i ) {
            ArrayList secList = new ArrayList();
            for( int n = 0 ; n < shades[i].length; n += 2 ) {
                HashMap child = new HashMap();
                child.put( "shadeName", shades[i][n] );
                child.put( "rgb", shades[i][n+1] ); secList.add( child );
            }
            result.add( secList );
        } 
        return result;
    }
}

【问题讨论】:

    标签: android checkbox expandablelistview


    【解决方案1】:

    这是我对这个问题的回答,你需要为单个孩子保持检查状态,并在点击孩子时检查它。经过一些研究,这是由于 android 的视图生命周期导致视图刷新,因此不保持状态。

    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;
    }
    

    }

    【讨论】:

    • 我不认为这是最佳变体..这只是一个解决方案..但性能低..
    【解决方案2】:

    我也有这个问题。最后我找到了根本原因和解决方案。要解决此问题,您应该设置其包含的 listView 的 checkState,而不是为 checkBox 设置 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;
      }
      ...
    }
    

    【讨论】:

      【解决方案3】:

      带多选的ExpandableListView。在 API 4.3 和 4.0.3 上测试 此代码还正确处理更改屏幕方向。通过 SparseBooleanArray 使阻塞组与所选元素正常工作。

      我希望这个示例代码会有所帮助:)

      活动

      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());
       }
      

      适配器

      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 类

      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 类

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

      子行布局

      <?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>
      

      组布局

      <?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>
      

      获取选定的子项

      final SparseBooleanArray checkedItems = list.getCheckedItemPositions();
      for (int i = 0; i < checkedItems.size(); i++) {
        if(checkedItems.valueAt(i))
          data = ((String)list.getItemAtPosition(checkedItems.keyAt(i)));
      }
      

      【讨论】:

      • 很好的例子但是第一个父节点项没有显示在列表中
      • 节省了我的时间。但公共布尔 onChildClick 不起作用。
      【解决方案4】:

      带有复选框的可扩展列表视图

      我们可以在 github 中获得完整的示例,该示例维护可扩展列表的复选框状态。

      点击链接获取Android Studio项目
      https://github.com/bhat-dinesh/ExpandableListViewWithCheckBox

      我希望这会有所帮助:)

      【讨论】:

      • 虽然指向外部资源的链接可能很有用,但应直接在 SO 帖子中包含答案的精髓。请相应地修改您的答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多