我已经从SO阅读了大约30页以及有关在列表中跟踪检查状态的教程,但是在可扩展ListView中这样做很少有信息(尤其是工作信息).
我让孩子们填充了复选框,但当我检查一组孩子的盒子时,其他组中的随机孩子也会检查.我需要阻止这一点.我认为我读到的最好的信息是将复选框设置为单独的标签,但我不知道如何设置多个标签,当我尝试时,我遇到了类错配错误,将复选框与转换视图进行比较.
有没有人遇到过在expandablelistview的孩子中跟踪复选框状态的好方法?
我做了多处更改,所以我要输入整个适配器代码.请检查几行getGroupView和整个getChildView,并帮我看看我做错了什么.
编辑:现在发生的事情是,当我选中一个框然后展开另一个组时,所有选中的框都取消选中:
public class MyExpandableListAdapter extends BaseExpandableListAdapter implements OnCheckedChangeListener { private Context mContext; private ArrayListmListDataHeader; private HashMap > mListDataChild; private boolean[] mGetChecked; private HashMap mChildCheckStates; private ArrayList selectedNumbers; private ChildViewHolder childViewHolder; private GroupViewHolder groupViewHolder; private String numberText; public MyExpandableListAdapter(Context context, ArrayList listDataHeader, HashMap > listDataChild, ArrayList listOfNumbers) { mContext = context; mListDataHeader = listDataHeader; mListDataChild = listDataChild; selectedNumbers = listOfNumbers; mChildCheckStates = new HashMap (); } @Override public int getGroupCount() { return mListDataHeader.size(); } @Override public ContactNameItems getGroup(int groupPosition) { return mListDataHeader.get(groupPosition); } @Override public long getGroupId(int groupPosition) { return groupPosition; } @Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { String contactName = getGroup(groupPosition).getName(); Bitmap contactImage = getGroup(groupPosition).getImage(); mGetChecked = new boolean[getChildrenCount(groupPosition)]; mChildCheckStates.put(contactName, mGetChecked); if (convertView == null) { LayoutInflater inflater = (LayoutInflater) mContext .getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.contact_name_item, null); groupViewHolder = new GroupViewHolder(); groupViewHolder.mContactName = (TextView) convertView .findViewById(R.id.lblListHeader); groupViewHolder.mContactImage = (ImageView) convertView .findViewById(R.id.ivContactPhoto); convertView.setTag(groupViewHolder); } else { groupViewHolder = (GroupViewHolder) convertView.getTag(); } if (contactImage != null) { groupViewHolder.mContactImage.setImageBitmap(contactImage); } else { groupViewHolder.mContactImage .setImageResource(R.drawable.default_contact); } groupViewHolder.mContactName.setText(contactName); return convertView; } @Override public int getChildrenCount(int groupPosition) { return mListDataChild.get(mListDataHeader.get(groupPosition).getName()) .size(); } @Override public ContactPhoneItems getChild(int groupPosition, int childPosition) { return mListDataChild.get(mListDataHeader.get(groupPosition).getName()) .get(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) { final String contactName = getGroup(groupPosition).getName(); final int mChildPosition = childPosition; numberText = getChild(groupPosition, childPosition).getNumber(); String typeText = getChild(groupPosition, childPosition).getPhoneType(); mGetChecked = mChildCheckStates.get(contactName); if (convertView == null) { LayoutInflater inflater = (LayoutInflater) this.mContext .getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.contact_detail_item, null); childViewHolder = new ChildViewHolder(); childViewHolder.mPhoneNumber = (TextView) convertView .findViewById(R.id.tv_phone_number); childViewHolder.mPhoneType = (TextView) convertView .findViewById(R.id.tv_phone_type); childViewHolder.mCheckBox = (CheckBox) convertView .findViewById(R.id.checkBox); convertView.setTag(R.layout.contact_detail_item, childViewHolder); } else { childViewHolder = (ChildViewHolder) convertView .getTag(R.layout.contact_detail_item); } childViewHolder.mPhoneNumber.setText(numberText); childViewHolder.mPhoneType.setText(typeText); childViewHolder.mCheckBox.setChecked(mGetChecked[mChildPosition]); childViewHolder.mCheckBox.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { boolean isChecked = childViewHolder.mCheckBox.isChecked(); Log.d("Debug", "isChecked = " + String.valueOf(isChecked)); if (isChecked) { selectedNumbers.add(numberText); } else { selectedNumbers.remove(numberText); } childViewHolder.mCheckBox.setChecked(isChecked); mGetChecked[mChildPosition] = isChecked; mChildCheckStates.put(contactName, mGetChecked); } }); return convertView; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return false; } @Override public boolean hasStableIds() { return false; } public ArrayList getSelectedNumbers() { return selectedNumbers; } public final class GroupViewHolder { TextView mContactName; ImageView mContactImage; } public final class ChildViewHolder { TextView mPhoneNumber; TextView mPhoneType; CheckBox mCheckBox; } @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { // TODO Auto-generated method stub Log.d("Debug", "onCheckChangedListener : " + String.valueOf(isChecked)); }
}
这是工作解决方案
好的,虽然互联网上似乎有很多关于可扩展列表视图中的复选框的建议,但没有一个对我有用.我能够在一群人的帮助下得到它,尤其是dev84.现在我不会声称这是完美的或万无一失的.我只是声称它对我有用.我已经在2台设备上进行了测试,我对此非常满意.
所以我已经把我的工作代码缩小到了它的基本部分,并添加了一些有用的评论,所以任何需要它的人都可以.希望它对你来说和我一样好用.请享用
import java.util.ArrayList; import java.util.HashMap; import java.util.List; import android.annotation.SuppressLint; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseExpandableListAdapter; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.TextView; // Eclipse wanted me to use a sparse array instead of my hashmaps, I just suppressed that suggestion @SuppressLint("UseSparseArrays") public class MyExpandableListAdapter extends BaseExpandableListAdapter { // Define activity context private Context mContext; /* * Here we have a Hashmap containing a String key * (can be Integer or other type but I was testing * with contacts so I used contact name as the key) */ private HashMap<String, List<ExpListChildItems>> mListDataChild; // ArrayList that is what each key in the above // hashmap points to private ArrayList<ExpListGroupItems> mListDataGroup; // Hashmap for keeping track of our checkbox check states private HashMap<Integer, boolean[]> mChildCheckStates; // Our getChildView & getGroupView use the viewholder patter // Here are the viewholders defined, the inner classes are // at the bottom private ChildViewHolder childViewHolder; private GroupViewHolder groupViewHolder; /* * For the purpose of this document, I'm only using a single * textview in the group (parent) and child, but you're limited only * by your XML view for each group item :) */ private String groupText; private String childText /* Here's the constructor we'll use to pass in our calling * activity's context, group items, and child items */ public MyExpandableListAdapter(Context context, ArrayList<ExpListGroupItems> listDataGroup, HashMap<String, List<ExpListChildItems>> listDataChild) { mContext = context; mListDataGroup = listDataGroup; mListDataChild = listDataChild; // Initialize our hashmap containing our check states here mChildCheckStates = new HashMap<Integer, boolean[]>(); } @Override public int getGroupCount() { return mListDataGroup.size(); } /* * This defaults to "public object getGroup" if you auto import the methods * I always make a point to change it from "object" to whatever item * I passed through the constructor */ @Override public ExpListGroupItems getGroup(int groupPosition) { return mListDataGroup.get(groupPosition); } @Override public long getGroupId(int groupPosition) { return groupPosition; } @Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { // I passed a text string into an activity holding a getter/setter // which I passed in through "ExpListGroupItems". // Here is where I call the getter to get that text groupText = getGroup(groupPosition).getGroupText(); if (convertView == null) { LayoutInflater inflater = (LayoutInflater) mContext .getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.group_item, null); // Initialize the GroupViewHolder defined at the bottom of this document groupViewHolder = new GroupViewHolder(); groupViewHolder.mGroupText = (TextView) convertView.findViewById(R.id.groupTextView); convertView.setTag(groupViewHolder); } else { groupViewHolder = (GroupViewHolder) convertView.getTag(); } groupViewHolder.mGroupText.setText(groupText); return convertView; } @Override public int getChildrenCount(int groupPosition) { return mListDataChild.get(mListDataGroup.get(groupPosition).getMyText()).size(); } /* * This defaults to "public object getChild" if you auto import the methods * I always make a point to change it from "object" to whatever item * I passed through the constructor */ @Override public ExpListChildItems getChild(int groupPosition, int childPosition) { return mListDataChild.get(mListDataGroup.get(groupPosition).getMyText()).get(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) { final int mGroupPosition = groupPosition; final int mChildPosition = childPosition; // I passed a text string into an activity holding a getter/setter // which I passed in through "ExpListChildItems". // Here is where I call the getter to get that text childText = getChild(mGroupPosition, mChildPosition).getChildText(); if (convertView == null) { LayoutInflater inflater = (LayoutInflater) this.mContext .getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.child_item, null); childViewHolder = new ChildViewHolder(); childViewHolder.mChildText = (TextView) convertView .findViewById(R.id.childTextView); childViewHolder.mCheckBox = (CheckBox) convertView .findViewById(R.id.checkBox); convertView.setTag(R.layout.child_item, childViewHolder); } else { childViewHolder = (ChildViewHolder) convertView .getTag(R.layout.child_item); } childViewHolder.mChildText.setText(childText); /* * You have to set the onCheckChangedListener to null * before restoring check states because each call to * "setChecked" is accompanied by a call to the * onCheckChangedListener */ childViewHolder.mCheckBox.setOnCheckedChangeListener(null); if (mChildCheckStates.containsKey(mGroupPosition)) { /* * if the hashmap mChildCheckStates<Integer, Boolean[]> contains * the value of the parent view (group) of this child (aka, the key), * then retrive the boolean array getChecked[] */ boolean getChecked[] = mChildCheckStates.get(mGroupPosition); // set the check state of this position's checkbox based on the // boolean value of getChecked[position] childViewHolder.mCheckBox.setChecked(getChecked[mChildPosition]); } else { /* * if the hashmap mChildCheckStates<Integer, Boolean[]> does not * contain the value of the parent view (group) of this child (aka, the key), * (aka, the key), then initialize getChecked[] as a new boolean array * and set it's size to the total number of children associated with * the parent group */ boolean getChecked[] = new boolean[getChildrenCount(mGroupPosition)]; // add getChecked[] to the mChildCheckStates hashmap using mGroupPosition as the key mChildCheckStates.put(mGroupPosition, getChecked); // set the check state of this position's checkbox based on the // boolean value of getChecked[position] childViewHolder.mCheckBox.setChecked(false); } childViewHolder.mCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked) { boolean getChecked[] = mChildCheckStates.get(mGroupPosition); getChecked[mChildPosition] = isChecked; mChildCheckStates.put(mGroupPosition, getChecked); } else { boolean getChecked[] = mChildCheckStates.get(mGroupPosition); getChecked[mChildPosition] = isChecked; mChildCheckStates.put(mGroupPosition, getChecked); } } }); return convertView; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return false; } @Override public boolean hasStableIds() { return false; } public final class GroupViewHolder { TextView mGroupText; } public final class ChildViewHolder { TextView mChildText; CheckBox mCheckBox; } }