CheckBox在ExpandableListView的子节点中声明

Pse*_*328 5 android expandablelistview android-checkbox

我已经从SO阅读了大约30页以及有关在列表中跟踪检查状态的教程,但是在可扩展ListView中这样做很少有信息(尤其是工作信息).

我让孩子们填充了复选框,但当我检查一组孩子的盒子时,其他组中的随机孩子也会检查.我需要阻止这一点.我认为我读到的最好的信息是将复选框设置为单独的标签,但我不知道如何设置多个标签,当我尝试时,我遇到了类错配错误,将复选框与转换视图进行比较.

有没有人遇到过在expandablelistview的孩子中跟踪复选框状态的好方法?

我做了多处更改,所以我要输入整个适配器代码.请检查几行getGroupView和整个getChildView,并帮我看看我做错了什么.

编辑:现在发生的事情是,当我选中一个框然后展开另一个组时,所有选中的框都取消选中:

public class MyExpandableListAdapter extends BaseExpandableListAdapter
    implements OnCheckedChangeListener {

private Context mContext;

private ArrayList<ContactNameItems> mListDataHeader;
private HashMap<String, List<ContactPhoneItems>> mListDataChild;

private boolean[] mGetChecked;
private HashMap<String, boolean[]> mChildCheckStates;

private ArrayList<String> selectedNumbers;

private ChildViewHolder childViewHolder;
private GroupViewHolder groupViewHolder;

private String numberText;

public MyExpandableListAdapter(Context context,
        ArrayList<ContactNameItems> listDataHeader,
        HashMap<String, List<ContactPhoneItems>> listDataChild,
        ArrayList<String> listOfNumbers) {

    mContext = context;
    mListDataHeader = listDataHeader;
    mListDataChild = listDataChild;
    selectedNumbers = listOfNumbers;

    mChildCheckStates = new HashMap<String, boolean[]>();
}

@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<String> 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));
}
Run Code Online (Sandbox Code Playgroud)

}

Pse*_*328 12

这是工作解决方案

好的,虽然互联网上似乎有很多关于可扩展列表视图中的复选框的建议,但没有一个对我有用.我能够在一群人的帮助下得到它,尤其是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;
    }
}
Run Code Online (Sandbox Code Playgroud)


and*_*v84 2

我看到你有一个selectedNumbers对象,那是什么类型的集合?拥有一个地图或列表或一些基于更独特的东西(例如组和子位置)的集合可能是最有意义的。然后你可以这样做:

(编辑:编辑代码以确保checkedChangedListener不会触发)(编辑2基于OP的更新):您可能不应该使用字符串到布尔数组的映射。而是尝试这个。它非常相似,但使用整数,这比字符串更容易比较

...
HashMap<Integer, Integer> mCheckedStates; // assume initialized as you did
...

childViewHolder.mPhoneNumber.setText(numberText);
childViewHolder.mPhoneType.setText(typeText);
childViewHolder.mCheckBox.setOnCheckedChangeListener(null);
if (mCheckedStates.contains(groupPosition)) {
    int checkedChildren = mCheckedStates.get(groupPosition);
    if ((checkedChildren & (1 << childPosition)) ==  1) {
        childViewHolder.mCheckBox.setChecked(true);
    } else {
        //Edit: Cannot rely on checkbox being false on Recycle,
        childViewHolder.mCheckBox.setChecked(false);
    }
}
childViewHolder.mCheckBox.setOnCheckedChangeListener(this);

@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

    // get group and child positions
    if (isChecked) {

        if (mCheckedStates.contains(groupPosition)) {
            // I'm using a bitmap to keep resources low, but it's not necessary to do it this way
            int childmap = mCheckedStates.get(groupPosition);
            childmap += (1 << childPosition);
            mCheckedStates.put(groupPosition, childmap);
        } else {
            mCheckedStates.put(groupPosition, (1 << childPosition));
        }
    } else {
        if (mCheckedStates.contains(groupPosition)) {
            int childmap = mCheckedStates.get(groupPosition);
            if (childmap == (1 << childPosition)) {
                mCheckedStates.remove(groupPosition);
            } else {
                childmap &= ~(1 << childPosition);
                mCheckedStates.put(groupPosition, childmap);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

}