Android ListView 显示多种数据类型

ListView往往可能会有不同的数据类型,单类型的数据可能运用会比较少些,这也是最近项目中的一个需求{在发送消息的时候,需要选择联系人,而联系人列表由英文字母索引+联系人组成},上一篇文章只是一个基调,这篇是更复杂的情况;
先看一下效果图
Android 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,通过几步就实现了所想要的功能!

你可能感兴趣的:(Android ListView 显示多种数据类型)