zoukankan      html  css  js  c++  java
  • Android ListView 显示多种数据类型

    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,通过几步就实现了所想要的功能!

  • 相关阅读:
    变量在函数内外的作用域 3
    php中用大括号把?>和<?php框起来的作用
    变量在函数内外的作用域 2
    变量在函数内外的作用域
    字母大小写对变量和函数的区别
    require()和include()代码重用
    str_place()替换函数
    【开源框架】Android之史上最全最简单最有用的第三方开源库收集整理,有助于快速开发,欢迎各位网友补充完善
    android SQLite使用SQLiteOpenHelper类对数据库进行操作
    tomcat设置IP地址或者域名访问
  • 原文地址:https://www.cnblogs.com/a284628487/p/3168597.html
Copyright © 2011-2022 走看看