ListView往往可能会有不同的数据类型,单类型的数据可能运用会比较少些,这也是最近项目中的一个需求{在发送消息的时候,需要选择联系人,而联系人列表由英文字母索引+联系人组成},上一篇文章只是一个基调,这篇是更复杂的情况;
先看一下效果图
最开始的时候,打算把两种数据类型放入一个List<Object>中,参考上一篇随笔的状态保持的实现,在代码写完了开始测试的时候,发现问题众多,上下滚动的时候左边的CheckBox的选择状态没有很好的保存,会出现混乱选择的情况,于是参考网上的一些做法{寻找的参考方法并没有描述像这样稍稍复杂点的情况,都是TextView,没有状态的保持,没有View的重用,所以写了这篇随笔}并延伸总结;
MutiTypeAdapter.java
public class MutiTypeAdapter extends BaseAdapter { private OnSelectedItemChanged listener; private List<ListItem> list; private LayoutInflater inflater; public MutiTypeAdapter(Context context, List<ListItem> list, OnSelectedItemChanged listener) { super(); this.list = list; inflater = LayoutInflater.from(context); this.listener = listener; } @Override public int getCount() { return list.size(); } @Override public Object getItem(int position) { return list.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { // 重点 View view = list.get(position).getView(convertView, inflater); if (list.get(position).getClass() == BEntity.class) { // 如果是BEntity,也就是上面图中左边有CheckBox的项 final BEntity entity = (BEntity) list.get(position); final CheckBox cb = entity.cbox; cb.setChecked(entity.isChecked()); cb.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { entity.setChecked(cb.isChecked()); // 更改List中Entity的选择状态 if (listener != null) { listener.onClick(getSelectedItem(list)); // 接口的思想暴露给Activity选择了多少项,当然也可以具体点通知Activity选择了哪些项 } } }); } return view; } public int getSelectedItem(List<ListItem> list) { // 获取选择了多少项 int i = 0; for (ListItem item : list) { if (item.isChecked()) { i++; } } return i; } public interface OnSelectedItemChanged { public void onClick(int count); } }
上面是数据源适配器,最开始的时候我在getView方法中对Item进行数据类的判断(AEntity/BEntity),再决定是选择加载哪一个layout,结果发现在重用View的时候很混乱,所以改为上面的实现方法;
AEntity和BEntity都继承自接口ListItem
public class AEntity implements ListItem { private String str; public AEntity(String str) { super(); this.str = str; } @Override public View getView(View convertView, LayoutInflater inflater) { Holder holder = null; if (convertView == null || convertView.getTag().getClass() != Holder.class) { holder = new Holder(); convertView = inflater.inflate(getLayoutId(), null); TextView tv = (TextView) convertView.findViewById(R.id.title_tv); holder.tv = tv; convertView.setTag(holder); } else { holder = (Holder) convertView.getTag(); } holder.tv.setText(str); return convertView; } class Holder { TextView tv; } @Override public int getLayoutId() { return R.layout.title; } @Override public boolean isChecked() { // 此Entity相当于是标题项,没有CheckBox,所以永远返回false return false; } }
public class BEntity implements ListItem { private boolean isChecked = false; private String str; public boolean isChecked() { return isChecked; } public void setChecked(boolean isChecked) { this.isChecked = isChecked; } public BEntity(String str) { super(); this.str = str; } @Override public int getLayoutId() { return R.layout.child; } public CheckBox cbox; @Override public View getView(View convertView, LayoutInflater inflater) { Holder holder = null; if (convertView == null || convertView.getTag().getClass() != Holder.class) { holder = new Holder(); convertView = inflater.inflate(getLayoutId(), null); TextView tv = (TextView) convertView.findViewById(R.id.item_tv); CheckBox cb = (CheckBox) convertView.findViewById(R.id.item_cb); holder.tv = tv; holder.cb = cb; convertView.setTag(holder); } else { holder = (Holder) convertView.getTag(); } holder.tv.setText(str); final CheckBox cb = holder.cb; this.cbox = cb;return convertView; } class Holder { TextView tv; CheckBox cb; } }
ListItem.java
public interface ListItem { public boolean isChecked(); // 当前项是否选中 public int getLayoutId(); public View getView(View convertView, LayoutInflater inflater); // 返回Adapter中需要返回的View }
在MainActivity中,模拟数据源并绑定到ListView列表;
public class MainActivity extends Activity { ListView lv; MutiTypeAdapter adapter; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); lv = (ListView) findViewById(R.id.lv); setAdapter(); } private void setAdapter() { List<ListItem> list = new ArrayList<ListItem>(); for (int i = 0; i < 50; i++) { if (i % 2 == 0) { list.add(new AEntity("item - " + i)); } else { list.add(new BEntity("item - " + i)); } } OnSelectedItemChanged listener = new OnSelectedItemChanged() { @Override public void onClick(int count) { Log.e("SelectedCount", count + ""); } }; adapter = new MutiTypeAdapter(getApplicationContext(), list, listener); lv.setAdapter(adapter); } }
OK,通过几步就实现了所想要的功能!