从头学android_ListView的使用

来源:互联网 发布:linux全局翻墙教程 编辑:程序博客网 时间:2024/06/05 04:36

需求

当界面上需要有多个条目需要显示的时候,而且条目数量不定,在xml文件中定义控件就无能为力了,这种情况下可以使用ListView,用来显示多个结构相同的条目,比如新闻客户端,应用市场app列表中,每个条目都是由相同的结构构成的,条目总数目来自于数据库,编程时未知。

步骤

首先定义一个Listview控件,找到它,设置它的适配器。

1. 定义控件

在布局文件中定义一个ListView控件,加上id方便获取,给予适当的宽高。

2. 设置Adapter

   这里常用的Adapter有三种,BaseAdapter,SimpleAdapter,ArrayAdapter。其中:

baseAdapter是一个抽象类,需要继承并实现抽象方法才能使用,封装较浅,最为灵活

SimpleAdapter是BaseAdapter的子类,能通过自定义布局作为每个条目的结构来显示。

ArrayAdapter也是BaseAdapter的子类,封装度很高,能够很简单的使用,但是只能用来显示单项文本。

使用 BaseAdapter

写一个Adapter继承BaseAdapter,实现四个方法

    class MyAdapter extends BaseAdapter {        //有系统调用,用来获知模型层有多少条数据        @Override        public int getCount() {            return plist.size();        }        @Override        public Object getItem(int position) {            return plist.get(position);        }        @Override        public long getItemId(int position) {            return position;        }        //由系统调用  返回的view对象就会作为listView的一个条目显示在屏幕上        @Override        public View getView(int position, View convertView, ViewGroup parent) {            View view;            //convertView就是已经缓存好的View对象,应尽量使用已经缓存的对象,节约内存            if (convertView == null) {                //获取条目的布局文件,将布局文件填充成view对象                view = View.inflate(MainActivity.this, R.layout.personlayout, null);            } else {                view = convertView;            }            //获取布局文件里面的控件            TextView tv_name = (TextView) view.findViewById(R.id.tv_name);            TextView tv_phone = (TextView) view.findViewById(R.id.tv_phone);            TextView tv_salary = (TextView) view.findViewById(R.id.tv_salary);<pre name="code" class="java">            //设置文本

Person person = plist.get(position); tv_name.setText(person.getName()); tv_phone.setText(person.getPhone()); tv_salary.setText(person.getSalary() + "");//如果参数是字符串,则设置字符串为文本值,如果参数是整数,则以整数为id去查找相应的资源 return view; } }


使用viewHolder;

还有一个性能优化的空间就是,每次从id中找控件,每次都是相同的id,得到相同的控件。使用viewholeder可以减少findviewbyId的次数,可以提高运行速度。

定义一个类,将控件作为其成员存在,在第一次调用getview的时候,实例化这个类,将所有findviewbyid得到的控件存入该实例,再将实例作为一个Tag保存在View中,这样,之后调用的都是缓存后的ConvertView,它的Tag肯定就是这个实例了,然后直接就可以使用这个实例的成员作为控件进行设置了。

        public View getView(int position, View convertView, ViewGroup parent) {            News news = newses.get(position);            View view;            MyViewHolder mhoder;            if (convertView == null) {                mhoder = new MyViewHolder();                view = View.inflate(MainActivity.this, R.layout.newslayout, null);                mhoder.tv_title = (TextView) view.findViewById(R.id.tv_title);                mhoder.tv_detail = (TextView) view.findViewById(R.id.tv_detail);                mhoder.tv_comment = (TextView) view.findViewById(R.id.tv_comment);                mhoder.imageView = (SmartImageView) view.findViewById(R.id.imageview);                view.setTag(mhoder);            } else {                view = convertView;                mhoder = (MyViewHolder) view.getTag();//这样的话,不管convertview是否为空,都能保证mholder是有值的。            }            mhoder.imageView.setImageUrl(news.getImagePath());            mhoder.tv_title.setText(news.getTitle());            mhoder.tv_detail.setText(news.getDetail());            mhoder.tv_comment.setText(news.getComment());            return view;        }        class MyViewHolder{            private TextView tv_title;            private TextView tv_detail;            private TextView tv_comment;            private SmartImageView imageView;        }

设置Adapter

if (lv != null) lv.setAdapter(new MyAdapter());
结果

使用SimpleAdapter

SimpleAdapter不是抽象类,直接new就可以使用

if (lv != null)            lv.setAdapter(new SimpleAdapter(MainActivity.this, data, R.layout.personlayout,                    new String[]{"name","phone","salary"},//data中map的key                    new int[]{R.id.tv_name, R.id.tv_phone, R.id.tv_salary}));//将map中的数据放到哪里去
构造函数参数: arg0 Context,arg1 List<Map<String,Object>>, arg2 int, arg3 String[], arg4 int[]

其中 arg1 (data) 是一个List,泛型是Map,map的泛型是<String,?>,每一个map可以理解为一个一个条目的数据,整个list就是所有的条目的数据,而map中的每一个键值对就是每一个条目中的一个部分的标志和值。

其中arg2是描述每一个条目的布局结构的布局文件的资源id。

arg3 是一个字符串数组,与Map<String,?>中的key String。

arg4 是一个int数组,描述的是将Map中Key所对应的value设置给哪些控件,如果对应的是ImageView,那么arg3中的value应该是图片的资源Id

如:

        for (Person person:plist             ) {            Map<String, Object> map = new HashMap<>();            map.put("name", person.getName());            map.put("phone", person.getPhone());            map.put("salary", person.getSalary());            data.add(map);        }
因为这里不过就是将BaseAdapter做了封装,使用的布局和数据都是一样的,所以运行结果和BaseAdapter是一样的

使用ArrayAdapter

ArrayAdapter封装度极高,只能将字符串数组作为data

if (lv!=null) lv.setAdapter(new ArrayAdapter<String>(MainActivity.this,R.layout.personlayout,R.id.tv_name,new String[]{"zhangsan","lisi"}))

可以看到定义的条目布局中只能有一个根据数据变动,应为它只能接收一个字符串数组作为data,但是使用起来也非常简单。

总结

Listview可以用来显示多条目的数据,作用就相当于JavaWeb MVC框架中的jsp。Adapter就相当于Servlet(Controller),是控制显示的。

三种Adapter各有不同,使用BaseAdapter的话,各种方法需要自己实现,如使用ConvertView来节约内存(不用的话后果很严重)等。而其他两个都已经实现好了,直接用就可以。最简单的实现就要用ArrayAdapter,需要显示特定结构的条目就需要使用SimpleAdapter,如果都不能满足,才应该考虑使用BaseAdapter。

0 0
原创粉丝点击