以前没发现的问题,使用ListView存放数据显示时,一般情况下使用时没问题,但是如果需要在ListView中的子控件改变状态时就出现问题了
看图, 选中了第1,2个,然后向下滚动,出现了没有选中的Item也被选中了,这样问题就出现了,每次改变状态时,在未知的地方也随机变化了?
MainActivity
1 package com.example.listviewscrollstatus; 2 3 import java.util.ArrayList; 4 import java.util.HashMap; 5 import java.util.List; 6 import java.util.Map; 7 8 import android.app.Activity; 9 import android.os.Bundle; 10 import android.widget.ListView; 11 12 public class MainActivity extends Activity { 13 14 ListView listView; 15 16 // 模拟数据源 17 int[] iconRes = { R.drawable.ic_launcher, R.drawable.ic_add, R.drawable.ic_add_selected }; 18 19 // 存放数据 20 private List<Map<String, Object>> dataList; 21 22 @Override 23 protected void onCreate(Bundle savedInstanceState) { 24 super.onCreate(savedInstanceState); 25 setContentView(R.layout.activity_main); 26 27 initListView(); 28 } 29 30 private void initListView() { 31 listView = (ListView) findViewById(android.R.id.list); 32 getData(); 33 34 listView.setAdapter(new ListContentAdapter(this, dataList)); 35 } 36 37 private void getData() { 38 39 dataList = new ArrayList<Map<String, Object>>(); 40 Map<String, Object> map; 41 // 模拟数据,放入对应的logo icon,title,set icon 42 for (int i = 0; i < 40; i++) { 43 map = new HashMap<String, Object>(); 44 map.put("icon", iconRes[i % 3]); // 轮流使用 45 map.put("title", "文字标题__" + i); 46 // map.put("set", ""); 47 48 dataList.add(map); 49 map = null; 50 } 51 } 52 53 }
Adapter
1 /** 2 * 3 */ 4 package com.example.listviewscrollstatus; 5 6 import java.util.List; 7 import java.util.Map; 8 9 import android.content.Context; 10 import android.view.LayoutInflater; 11 import android.view.View; 12 import android.view.ViewGroup; 13 import android.widget.BaseAdapter; 14 import android.widget.CheckBox; 15 import android.widget.ImageButton; 16 import android.widget.ImageView; 17 import android.widget.TextView; 18 19 /** 20 * @Description 21 * @author act262 22 * @version 1.0 23 * @since 2014-6-21 下午5:58:38 24 * 25 */ 26 public final class ListContentAdapter extends BaseAdapter { 27 private Context mContext; 28 private List<Map<String, Object>> mList; 29 private ViewHolder viewHolder = null; 30 31 public ListContentAdapter(Context context, List<Map<String, Object>> list) { 32 this.mContext = context; 33 this.mList = list; 34 } 35 36 // 在绘制ListView时调用该方法 37 @Override 38 public int getCount() { 39 return mList.size(); 40 } 41 42 // 返回指定位置的Item 43 @Override 44 public Object getItem(int position) { 45 return mList.get(position); 46 } 47 48 // 不指定id,一般为当前的位置 49 @Override 50 public long getItemId(int position) { 51 return position; 52 } 53 54 /** 55 * 自定义Adapter的最重要的方法: 使用ViewHolder作为一个缓存的对象,可以减少findViewById(); 56 * 假设一个ListView的空间一次加载10个item,也就是有对应的View 57 * 容器ConvertView10个,每次使viewHolder指向该ConvertView,第一个加载时convertView 58 * 为null,以后就不是null了; 当滚动ListView时,convertView不为null,从viewholder获取到缓存的视图数据, 59 */ 60 @Override 61 public View getView(int position, View convertView, ViewGroup parent) { 62 63 if (null == convertView) { 64 convertView = LayoutInflater.from(mContext).inflate(R.layout.view_listview_item, null); 65 66 viewHolder = new ViewHolder(); 67 viewHolder.iconView = (ImageView) convertView.findViewById(R.id.iv_icon); 68 viewHolder.titleView = (TextView) convertView.findViewById(R.id.tv_title); 69 viewHolder.selectView = (CheckBox) convertView.findViewById(R.id.cb_select); 70 viewHolder.setButton = (ImageButton) convertView.findViewById(R.id.ib_set); 71 72 convertView.setTag(viewHolder); 73 } else { 74 viewHolder = (ViewHolder) convertView.getTag(); 75 } 76 77 viewHolder.iconView.setImageResource((Integer) mList.get(position).get("icon")); 78 viewHolder.titleView.setText((CharSequence) mList.get(position).get("title")); 79 // viewHolder.selectView.setChecked(checked); 80 // viewHolder.selectView.setBackgroundResource(); 81 82 return convertView; 83 } 84 85 private final class ViewHolder { 86 ImageView iconView; 87 TextView titleView; 88 CheckBox selectView; 89 ImageButton setButton; 90 } 91 92 }
为了实现能够保留住当前的状态,需要使用记录来处理
1 // 用户记住CheckBox的状态 2 private Map<Integer, Boolean> selectStaus; 3 4 public ListContentAdapter(Context context, List<Map<String, Object>> list) { 5 this.mContext = context; 6 this.mList = list; 7 8 selectStaus = new HashMap<Integer, Boolean>(); 9 // 初始状态全部为不选中状态,故设为false 10 for (int i = 0; i < list.size(); i++) { 11 // 使用当前的位置作为key,boolean作为value 12 selectStaus.put(i, false); 13 } 14 }
在getView中加上后就能记住listview下的某个子控件的状态了。
1 viewHolder.selectView.setChecked(selectStaus.get(position)); 2 3 viewHolder.selectView.setOnClickListener(new OnClickListener() { 4 5 @Override 6 public void onClick(View v) { 7 // 记录状态改变了 8 selectStaus.put(position, viewHolder.selectView.isChecked()); 9 } 10 });
最后附上工程Demo