ListView 复用导致 CheckBox 选中状态错乱

在ListView嵌套CheckBox 等一些有标记的View时,如果不做处理,在ListView 滑动的时候,

会造成View的选中状态错乱。

比如:

可以看到 刚开始选中了demo2 和demo3。滑动到下一页的时候,demo10 和demo11 也被选中。

当然要解决这个问题很简单。只需要在 适配器Adapter 中对CheckBox的选中状态做一下记录。上代码:


public class MyAdapter extends BaseAdapter{
		private List<String> mList;
		private Context mContext;
		//步骤1
		private Map<Integer, Boolean> cbState;// 存放 CheckBox 的选中状态
		
		public MyAdapter(Context mContext,List<String> mList) {
			this.mContext=mContext;
			this.mList=mList;
			cbState=new HashMap<Integer, Boolean>();
		}

		@Override
		public int getCount() {
			return mList!=null?mList.size():0;
		}

		@Override
		public Object getItem(int position) {
			return mList!=null?mList.get(position):null;
		}

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

		@Override
		public View getView(final int position, View convertView, ViewGroup parent) {
			ViewHolder holder = null;
			if(convertView==null){
				convertView=LayoutInflater.from(mContext).inflate(R.layout.demo_item, parent,false);
				holder=new ViewHolder(convertView);
				convertView.setTag(holder);
			}else{
				holder=(ViewHolder)convertView.getTag();
			}
			holder.textView.setText(mList.get(position));
			
			// 步骤2 对checkbox 的选中状态进行监听,选中时,存入Map 集合,取消选中,则从集合中移除
			holder.checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
				
				@Override
				public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
					
					if(isChecked){
						cbState.put(position, true);
					}else{
						cbState.remove(position);
					}
				}
			});
			
		// 步骤3 对Map集合进行判断,处理checkBox 的选中状态
			if(cbState!=null&&cbState.containsKey(position)){
				holder.checkBox.setChecked(true);
			}else{
				holder.checkBox.setChecked(false);
			}
			return convertView;
		}
		private class ViewHolder{
			private TextView textView;
			private CheckBox checkBox;
			public ViewHolder(View view) {
				if(view==null)
					return;
				textView=(TextView)view.findViewById(R.id.demo_tv);
				checkBox=(CheckBox)view.findViewById(R.id.demo_cb);
			}
		}
	}
 这样写就可以解决问题。

注意:

如果 步骤2 和步骤3 的顺序写反了,即把对checkBox 的监听方法,写到了checkBox 设置状态的下面了。仍然会导致选中状态错乱。

如图所示:


可以看到 我选中了demo0 和demo1 ,滑下去在滑上来,选中状态就变成了未选中。

通过抓Log,发现,如果两者的顺序写反了,当状态再次改变时,

setOnCheckedChangeListener

监听方法中的position,使用的是上次点击时的postion 。

具体原因还没搞明白,以后会补充。

记住,两者的顺序一定不要写反。要把监听方法写在CheckBox设置状态上面。




  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
是的,当 ListView 滚动时,会导致 CheckBox选中状态消失。这是因为 ListView 会对其子项进行复用,从而导致 CheckBox状态丢失。 为了解决这个问题,可以在 Adapter 中使用 ViewHolder 模式来缓存 ListView 的子项,从而避免 CheckBox 状态的丢失。具体来说,ViewHolder 模式可以通过以下步骤来实现: 1. 在 Adapter 中定义一个 ViewHolder 类,用于缓存 ListView 的子项: ```java private static class ViewHolder { TextView nameTextView; CheckBox checkBox; } ``` 2. 在 getView 方法中使用 ViewHolder 对象来缓存 ListView 的子项: ```java @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder; if (convertView == null) { convertView = LayoutInflater.from(context).inflate(R.layout.list_item, parent, false); viewHolder = new ViewHolder(); viewHolder.nameTextView = convertView.findViewById(R.id.name_text_view); viewHolder.checkBox = convertView.findViewById(R.id.checkbox); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } // 设置子项的文本和 CheckBox 状态 MyItem item = getItem(position); viewHolder.nameTextView.setText(item.getName()); viewHolder.checkBox.setChecked(item.isChecked()); // 返回子项视图 return convertView; } ``` 在这个例子中,我们首先通过 convertView 参数来获取 ListView 的子项视图。如果 convertView 为 null,说明当前子项没有被缓存,我们就需要创建一个新的 ViewHolder 对象,并使用 setTag 方法将其绑定到 convertView 上。如果 convertView 不为 null,说明当前子项已经被缓存了,我们就可以直接从 convertView 中获取 ViewHolder 对象。 在 getView 方法中,我们通过 ViewHolder 对象来设置子项的文本和 CheckBox 状态。由于 CheckBox状态已经被缓存到 ViewHolder 中,因此即使 ListView 滚动,CheckBox状态也不会丢失。 最后,我们返回子项视图 convertView。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值