Android:ListViews和CheckBoxes的问题

时间:2010-09-07 02:38:11

标签: java android listview checkbox

我有一个ListView,在每个列表项中我都有一些TextView和一个CheckBox。当我检查一个CheckBox并且我的onCheckedChangeListener触发时,一切正常。但是,一旦选中一个,就会检查随机的其他复选框。这是一个例子。

如果我点击第一个CheckBox: 检查8。 检查15。 检查21。 检查27。 检查33。 检查41。 然后如果我一直向上滚动,直到6都没有检查。下一个是13。

基本上......发生了什么事?

6 个答案:

答案 0 :(得分:10)

您似乎正在重复使用您实施的convertView方法传递的getView()

Android会尝试对ListView中的不同项使用相同的视图。您将需要(1)手动取消选中/检查返回项目内的复选框(在返回getView之前始终调用setChecked或(2)不使用convertView,但从getView返回新视图。

我认为

(1)是推荐的。

答案 1 :(得分:6)

对我来说很好用

public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {

        final ViewHolder holder;
        final Season season = (Season) getGroup(groupPosition);
        if (convertView == null) {
            LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = vi.inflate(R.layout.season, parent, false);
            holder = new ViewHolder();
            holder.title = (TextView) convertView.findViewById(R.id.season_title);
            holder.checkBox = (CheckBox) convertView.findViewById(R.id.season_check_box);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        holder.title.setText(season.getTitle());
        holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                season.setChecked(isChecked);
                adapter.notifyDataSetChanged();
            }
        });

        holder.checkBox.setChecked(season.isChecked()); // position is important! Must be before return statement!
        return convertView;
    }

    protected class ViewHolder {
        protected TextView title;
        protected CheckBox checkBox;
    }

答案 2 :(得分:0)

我也面临着类似的问题之王,所以经过大量的阅读后我解决了这个问题:

@Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.listview, null);
            holder = new ViewHolder();
            holder.nameView = (TextView)convertView.findViewById(R.id.textView1);
            holder.numberView = (TextView)convertView.findViewById(R.id.textView2);
            holder.cb = (CheckBox)convertView.findViewById(R.id.checkBox1);
            convertView.setTag(holder);                
        } else {
            holder = (ViewHolder)convertView.getTag();
        }
        holder.nameView.setText(mData.get(position).toString());
        holder.numberView.setText(mNumber.get(position).toString());
        holder.cb.setChecked(false);
        holder.cb.setTag(position);



        if(selected.indexOf(mNumber.get(position).toString()) >= 0) // Check whether this row checkbox was checked, for that we previously stored the textview text in selected variable
        {

        holder.cb.setChecked(true);
        }

        return convertView;
    }

}

这里我在getView()上做了什么我取消选中所有复选框并再次手动检查我需要根据它对应的textview检查的那些。因此,如果用户在选中第一个复选框后向下滚动,则视图中的所有复选框都将取消选中,如果他再次向上滚动,则所有复选框都将被取消选中,但之后单击的复选框将再次重新检查。

答案 3 :(得分:0)

通过保持CheckBox状态可以轻松解决问题。自定义和解释完整的样本类代码如下_

 public class AreaDataAdapter extends ArrayAdapter<String> {
    private List<String> areaList;
    private Activity context;
    ArrayList<Boolean> positionArray;

    public AreaDataAdapter(Context context, int textViewResourceId,
            List<String> offersAreaList) {
        super(context, textViewResourceId, offersAreaList);
        // TODO Auto-generated constructor stub
        this.context=context;
        this.areaList = offersAreaList;

         positionArray = new ArrayList<Boolean>(offersAreaList.size());
            for(int i =0;i<offersAreaList.size();i++){
                positionArray.add(false);
          }

    }

    public AreaDataAdapter(Activity context, List<String> offersAreaList) {
        super(ShowOffersActivity.this, R.layout.filterlist_row, offersAreaList);
        this.context=context;
        this.areaList=offersAreaList;

         positionArray = new ArrayList<Boolean>(offersAreaList.size());
            for(int i =0;i<offersAreaList.size();i++){
                positionArray.add(false);
          }

    }

    public View getView(final int position, View convertView,ViewGroup parent) {
        View row=convertView;
        FilterViewHolder holder;
        if (row==null) {
            LayoutInflater inflater=getLayoutInflater();

            row=inflater.inflate(R.layout.filterlist_row, parent, false);
            holder = new FilterViewHolder();
            holder.filterCheckBox = (CheckBox)row.findViewById(R.id.filter_checkbox);
            holder.filterCheckBox.setTypeface(fontFace);

            row.setTag(holder);
        } else {
            //holder = (View) row;
            holder = (FilterViewHolder) row.getTag();

            /* When a listview recycles views , it recycles its present state as well as listeners attached to it.
             * if the checkbox was checked and has a onCheckedChangeListener set, both will remain a part of 
             * recycled view based on position. So it is our responsibility to reset all states and remove
             *  previous listeners.
             *  The listener was removed as below:-
             */
            holder.filterCheckBox.setOnCheckedChangeListener(null);

        }

            holder.filterCheckBox.setText(areaList.get(position));
            holder.filterCheckBox.setFocusable(false);
            holder.filterCheckBox.setChecked(positionArray.get(position));
            holder.filterCheckBox.setText(areaList.get(position));

            holder.filterCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {

                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    // TODO Auto-generated method stub
                    if (isChecked) {
                        //change state of concern item in 'positionArray' array to 'True'
                         positionArray.set(position, true);
                        //add the checked item in to area list which used to filter offers.
                        filterOffersByThisAreaList.add(areaList.get(position));

                    } else {
                       //change state of concern item in 'positionArray' array to 'True'
                         positionArray.set(position, true);
                        //remove the unchecked item in to area list which used to filter offers.
                        filterOffersByThisAreaList.remove(areaList.get(position));

                    }
                }
            });
        return row;
    }

}

包含这些(filterlist_row)的{​​{1}}的自定义行ListView如下所示_

CheckBox

自定义<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <CheckBox android:id="@+id/filter_checkbox" style="@style/CodeFont" android:button="@drawable/bg_custom_checkbox" android:text="Indian" /> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="#c9c9c3" /> </LinearLayout> 背景信息如下_

CheckBox

答案 4 :(得分:0)

我的切换视图遇到了同样的问题。经过大量的搜索和阅读,我发现这个问题是Android推出的一种优化视图的结果。它尝试重用视图对象。因此,基本上,当您单击开关或复选框时,您也会在另一个视图中触发更改回调。优化确实有效,但如果你不注意,或者只是不知道行为(像我一样),就会发生一些非常奇怪的结果。

无论如何,我找到了这个简单的解决方案:

最佳做法是重用在getView()方法上传递的convertView。这样就可以优化listview使用的Ram数量。所以我将我的视图存储在ViewHolder中并编写了onCheckedChanged事件。诀窍是,在设置之前如果检查了开关(在你的情况下,检查复选框)并定义CheckedChange监听器,我只需用null重置回调,这可以确保不触发另一个开关的事件

以下是摘录:

...
viewHolder.switchView.setOnCheckedChangeListener(null);
viewHolder.switchView.setChecked(myObject.getStatus() > 0);
...
viewHolder.switchView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                ...
            }
        });

myObject是存储Cursor数据的最终对象。

无论是否检查开关,都必须调用setChecked方法。

希望它有所帮助!

答案 5 :(得分:0)

@Override
public int getViewTypeCount() {
    return getCount();
}

@Override
public int getItemViewType(int position) {
    return position;
}

@Override
public int getCount() {
    return names.length;
}

@Override
public long getItemId(int position) {
    return 0;
}

在自定义适配器中添加此方法。它为我工作