带有Checkbox的Android ExpandableListView,控制已检查状态

时间:2011-02-21 16:45:27

标签: android checkbox expandablelistview

我正在尝试编写一个在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;
    }
}

4 个答案:

答案 0 :(得分:12)

这是我对这个问题的回答,你需要为个别孩子保持检查状态,并在点击孩子时检查它。经过一番研究,这是由于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;
}

}

答案 1 :(得分: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;
  }
  ...
}

答案 2 :(得分:1)

ExpandableListView with multiselect。在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)));
}

答案 3 :(得分:0)

带有复选框的可扩展ListView

我们可以在github中获得完整的例子,它保持可扩展列表的复选框状态。

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

我希望这有帮助:)