Fragment中SimpleAdapter实现ListView多选的视图复用问题求助
解决ListView复用导致选中状态混乱的问题
核心问题在于ListView的convertView复用机制:你直接在点击事件里临时修改View背景,但滚动时复用的View会保留之前的状态,没有根据checkedValue中的选中状态重新渲染,导致未触碰的项出现错误的视觉状态。
解决方案
不要在点击事件里直接修改View背景,而是通过自定义Adapter,在getView方法中根据checkedValue集合动态设置每个项的背景,点击事件只负责更新选中集合并通知Adapter刷新。
1. 自定义SimpleAdapter
继承系统的SimpleAdapter,重写getView方法,每次渲染项时根据当前项的RFID是否在选中集合中设置背景色:
public class CustomTagAdapter extends SimpleAdapter { private ArrayList<String> checkedValue; private Context context; public CustomTagAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to, ArrayList<String> checkedValue) { super(context, data, resource, from, to); this.context = context; this.checkedValue = checkedValue; } @Override public View getView(int position, View convertView, ViewGroup parent) { View view = super.getView(position, convertView, parent); // 获取当前项的RFID TextView tvTagUii = view.findViewById(R.id.TvTagUii); String rfid = tvTagUii.getText().toString(); // 根据选中状态设置背景 if (checkedValue.contains(rfid)) { view.setBackgroundColor(context.getResources().getColor(R.color.gray1)); } else { view.setBackgroundColor(context.getResources().getColor(R.color.white)); } return view; } }
2. 替换原Adapter初始化代码
用自定义Adapter替代原SimpleAdapter,传入checkedValue集合:
checkedValue = new ArrayList<>(); LvTags = (ListView) rootView.findViewById(R.id.LvTags); // 使用自定义Adapter adapter = new CustomTagAdapter(getContext(), tagList, R.layout.listtag_items, new String[]{"tagUii", "tagacsii","tagLen", "tagCount", "tagRssi"}, new int[]{R.id.TvTagUii, R.id.TvTagAcsii, R.id.TvTagLen, R.id.TvTagCount, R.id.TvTagRssi}, checkedValue); LvTags.setAdapter(adapter);
3. 修改点击事件逻辑
点击事件中只负责更新checkedValue集合,然后调用adapter.notifyDataSetChanged()通知Adapter刷新所有项的状态:
LvTags.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { TextView textView = (TextView) view.findViewById(R.id.TvTagUii); String RFID = textView.getText().toString(); porcelainReceivingMessage.setText(""); insqldata = checkInSql("RFID", RFID); if (!insqldata) { boolean insqlite = checkInSqlite("RFID", RFID); if (insqlite) { Toast.makeText(getContext(), "Tag in already scanned", Toast.LENGTH_SHORT).show(); } else { if (checkedValue != null && checkedValue.contains(RFID)) { checkedValue.remove(RFID); Log.d("deselect" + position, RFID); } else { checkedValue.add(RFID); Toast.makeText(getContext(), "Long click to add this tag to scanned items", Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), "Item selected", Toast.LENGTH_SHORT).show(); } // 更新选中数量 selectedCount.setText(String.valueOf(checkedValue.size())); // 通知Adapter刷新,重新渲染所有项 adapter.notifyDataSetChanged(); } } else if (insqldata) { Toast.makeText(getContext(), "Tag in already in SQL DB", Toast.LENGTH_SHORT).show(); } Log.d("checkedValue", String.valueOf(checkedValue)); } });
为什么之前的方法无效
你之前尝试的直接修改View背景、调用setItemChecked等方法,都是临时修改单个View的状态,但ListView滚动时会复用已滑出屏幕的View,这些复用的View不会自动同步checkedValue的最新状态,必须在Adapter的getView方法中每次都根据数据源重新设置,才能保证所有项显示正确的选中状态。
内容的提问来源于stack exchange,提问作者Ahsan
相关产品推荐
相关产品推荐

