吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 5395|回复: 18
收起左侧

[其他转载] Android之ListView详解

[复制链接]
awareness 发表于 2016-9-22 19:05
本帖最后由 awareness 于 2016-9-22 19:12 编辑

前文ListView作为Android最常用的控件之一,同时也是最难的控件之一,其难点主要在意用法的多变性,因此让众多的初学者都比较难掌握,包括我自己,也是在反复需要使用时,总会卡住.而在网上找了众多的ListView的实例,案例等,讲解得不尽人意,甚至让许多初学者有迷惑.所以才觉得写此文,将包括ListView的用法,具体的注解,详解以及方案,希望能帮到需要的人,若有不正之处还请指正,谢谢

由于ListView有指定的外观形式的,在此就不会使用那些

ListView显示数据的原理与javaweb相比较:                javaweb                                                Android
                        m:                    mode                                                        mode    数据javabean

                        v:                      view                                                          view    listview

                        c:                     controller servlet                                      adapter


注意事项:使用listview高的时候用了wrap_contant会降低效率,jvm会在后台不停的配置, 所以用listview是要用match_contant


ListView显示复杂的页面
    通过打气筒inflate可以把一个布局转换成一个view对象

获取打气筒常用的api
  • //第一种
  • view = View.inflate(MainActivity.this, R.layout.item, null);
  • //第二种
  • view=LayoutInflater.from(MainActivity.this).inflate(R.layout.item, null);
  • //第三种
  • LayoutInflater inflater= (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
  • view = inflater.inflate(R.layout.item, null);





ListView之指定列表项(无适配器)1.定义ListView属性
  •     <!-- ListView支持的常用xml属性 -->
  •     <!-- android:divider:为listview设置分隔条,可以定颜色,也可以用Drawable资源分割 -->
  •     <!-- android:dividerHeight:设置分隔条的高度 -->
  •     <!-- android:entries:用于数组资源为ListView指定列表项 -->
  •     <!-- android:footerDividersEnabled:用于设置是否在footer View前绘制分隔条,默认为true ,设置为false时表示不绘制,使用该组件时,需要通过ListView组件提供的addFooterView()方法为ListView设置footer View -->
  •     <!-- android:headerDividersEnabled:用于设置是否在herader View前绘制分隔条,默认为true ,设置为false时表示不绘制,使用该组件时,需要通过ListView组件提供的addHeaderView()方法为ListView设置header View -->
  •     <ListView
  •         android:id="@+id/lv"
  •         android:layout_width="match_parent"
  •         android:layout_height="match_parent"
  •         android:divider="@android:color/background_dark"
  •         android:dividerHeight="2dp"
  •         android:entries="@array/ctype"
  •         android:footerDividersEnabled="false"
  •         android:headerDividersEnabled="false" >
  •     </ListView>

2.由于属性中定义了从type的数组资源,所以在res/value目录中创建一个定义的数组资源的xml文件array.xml

  • <?xml version="1.0" encoding="utf-8"?>
  • <resources>
  •     <string-array name="ctype">
  •         <item>你好</item>
  •         <item>我是老司机</item>
  •         <item>你了?</item>
  •         <item>交个朋友怎么样?</item>
  •     </string-array>
  • </resources>



3.运行即可
属性添加了android:footerDividersEnabled="false"     android:headerDividersEnabled="false"
file:///F:/%E7%AC%94%E8%AE%B0/temp/7c3314e7-e831-4e98-9e52-0e671208da4b/4/index_files/829c8791-514e-4d65-b600-8811b486b946.jpg      
属性没有添加android:footerDividersEnabled="false"        android:headerDividersEnabled="false"
file:///F:/%E7%AC%94%E8%AE%B0/temp/7c3314e7-e831-4e98-9e52-0e671208da4b/4/index_files/31ea0d61-f17b-461e-a26e-ba1b9b964793.jpg
     由于没有设置ListView的样式没有设置内边距,所以第一条目看不出是否有分隔条


ListView之ArrayAdapter1,定义ListView属性(省略了咯)

2,在layout文件夹创建xml文件item来展示单个条目样式(可以有更多的样式设计)
  •     <TextView
  •         android:id="@+id/tv"
  •         android:layout_width="wrap_content"
  •         android:layout_height="wrap_content"
  •         android:textColor="@android:color/background_dark"
  •         android:textSize="20sp" />


3,定义需要展示的数组(注意是数组)
  • public class MainActivity extends Activity {
  •         private static String[] data = { "apple", "orange", "watermelon", "banana",
  •                         "pear", "cherry", "strawberry", "grape" };
  •         @Override
  •         protected void onCreate(Bundle savedInstanceState) {
  •                 super.onCreate(savedInstanceState);
  •                 setContentView(R.layout.activity_main);
  •                 ListView lv = (ListView) findViewById(R.id.lv);

  •                 // CharSequence与String都能用于定义字符串,但CharSequence的值是可读可写序列,而String的值是只读序列
  •                 ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(
  •                                 getApplicationContext(), //上下文,也可以是this和MainActivity.this
  •                                 R.layout.item, //注意是int类型,需要展示的容器
  •                                 R.id.tv, //注意是int类型,需要展示的具体控件
  •                                 data//需要展示的数据
  •                                 );
  •                 lv.setAdapter(adapter);
  •         }

注意选择适配器构造方法有多种,根据需求来选择,这里只给出一中来,原则就是要什么给什么


使用ArrayAdapter实现图文结合(此方法也适合单独的数组,条列更清晰)通过创建list集合对象和map键值对来存储一组数据
1.创建一个Fruit类,实现其中的getter()与setter()和构造函数
  • public class Fruit {
  •         private String name;
  •         private int imageId;
  •         public String getName() {
  •                 return name;
  •         }
  •         public void setName(String name) {
  •                 this.name = name;
  •         }
  •         public int getImageId() {
  •                 return imageId;
  •         }
  •         public void setImageId(int imageId) {
  •                 this.imageId = imageId;
  •         }
  •         public Fruit(String name, int imageId) {
  •                 super();
  •                 this.name = name;
  •                 this.imageId = imageId;
  •         }
  • }


2,在layout文件夹创建xml文件item来展示单个条目样式(可以有更多的样式设计)


  •   <ImageView
  •         android:id="@+id/iv"
  •         android:layout_width="wrap_content"
  •         android:layout_height="wrap_content"
  •         />
  •     <TextView
  •         android:id="@+id/tv"
  •         android:layout_width="wrap_content"
  •         android:layout_height="wrap_content"
  •         android:textColor="@android:color/background_dark"
  •         android:textSize="20sp" />



3,创建一个自定义的适配器并继承ArrayAdapter,泛型指定为Fruit
  • public class myAdapter extends ArrayAdapter<Fruit> {
  •         private int resourceId;
  •         public myAdapter(Context context, int textViewResourceId,
  •                         List<Fruit> objects) {
  •                 super(context, textViewResourceId, objects);
  •                 resourceId = textViewResourceId;
  •         }
  •         @Override
  •         public View getView(int position, View convertView, ViewGroup parent) {
  •                 Fruit fruit = getItem(position);
  •                 View view=LayoutInflater.from(getContext()).inflate(resourceId, null);
  •                
  •                 ImageView iv=(ImageView) view.findViewById(R.id.iv);
  •                 TextView tv = (TextView) view.findViewById(R.id.tv);
  •                 iv.setImageResource(fruit.getImageId());
  •                 tv.setText(fruit.getName());
  •                 return view;
  •         }
  • }



4.创建集合,初始化数据并实现
  • public class MainActivity extends Activity {
  •         //创建一个集合,存储数据
  •         private List<Fruit> fruitList = new ArrayList<Fruit>();
  •         @Override
  •         protected void onCreate(Bundle savedInstanceState) {
  •                 super.onCreate(savedInstanceState);
  •                 setContentView(R.layout.activity_main);
  •                 //需要展示的数据初始化
  •                 initFruit();
  •                 //通过适配器,用创建好的条目样式文件展示对应存储的数据(形成一个条目展示一组数据)
  •                 myAdapter adapter = new myAdapter(MainActivity.this, R.layout.item,
  •                                 fruitList);
  •                 ListView lv = (ListView) findViewById(R.id.lv);
  •                 lv.setAdapter(adapter);
  •         }
  •         private void initFruit() {
  •                 Fruit apple = new Fruit("apple", R.drawable.i1);
  •                 fruitList.add(apple);
  •                 Fruit orange = new Fruit("orange", R.drawable.i2);
  •                 fruitList.add(orange);
  •                 Fruit watermelon = new Fruit("watermelon", R.drawable.i3);
  •                 fruitList.add(watermelon);
  •                 Fruit banana = new Fruit("banana", R.drawable.i4);
  •                 fruitList.add(banana);
  •                 Fruit pear = new Fruit("pear", R.drawable.i5);
  •                 fruitList.add(pear);
  •                 Fruit cherry = new Fruit("cherry", R.drawable.i6);
  •                 fruitList.add(cherry);
  •                 Fruit strawberry = new Fruit("strawberry", R.drawable.i7);
  •                 fruitList.add(strawberry);
  •                 Fruit grape = new Fruit("grape", R.drawable.i8);
  •                 fruitList.add(grape);
  •         }
  •         



5.运行结果
file:///F:/%E7%AC%94%E8%AE%B0/temp/7c3314e7-e831-4e98-9e52-0e671208da4b/4/index_files/2194fcea-c757-4cdc-bf51-e43fc290d368.jpg







ListView之SimpleAdapter1,可以将MainActivity继承ListActivity,然后setListAdapter(adapter)实现适配器
2,定义listview与item的xml样式文件(上面有就省略了)
  • public class MainActivity extends Activity {
  •         @Override
  •         protected void onCreate(Bundle savedInstanceState) {
  •                 super.onCreate(savedInstanceState);
  •                 setContentView(R.layout.activity_main);
  •                 SimpleAdapter adapter = new SimpleAdapter(this, getData(),
  •                                 R.layout.item, new String[] { "iv", "tv",  },
  •                                 new int[] { R.id.iv, R.id.tv });
  •                 ListView lv = (ListView) findViewById(R.id.lv);
  •                 lv.setAdapter(adapter);
  •         }
  •         private List<Map<String, Object>> getData() {
  •                 List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
  •                 Map<String, Object> map = new HashMap<String, Object>();
  •                 map.put("iv", R.drawable.i1);
  •                 map.put("tv", "G1");
  •                 list.add(map);
  •                 map = new HashMap<String, Object>();
  •                 map.put("tv", "G2");
  •                 map.put("iv", R.drawable.i2);
  •                 list.add(map);
  •                 map = new HashMap<String, Object>();
  •                 map.put("tv", "G3");
  •                 map.put("iv", R.drawable.i3);
  •                 list.add(map);
  •                 map = new HashMap<String, Object>();
  •                 map.put("tv", "G3");
  •                 map.put("iv", R.drawable.i4);
  •                 list.add(map);
  •                 map = new HashMap<String, Object>();
  •                 map.put("tv", "G3");
  •                 map.put("iv", R.drawable.i5);
  •                 list.add(map);
  •                 map = new HashMap<String, Object>();
  •                 map.put("tv", "G3");
  •                 map.put("iv", R.drawable.i6);
  •                 list.add(map);
  •                 map = new HashMap<String, Object>();
  •                 map.put("tv", "G3");
  •                 map.put("iv", R.drawable.i7);
  •                 list.add(map);
  •                 map = new HashMap<String, Object>();
  •                 map.put("tv", "G3");
  •                 map.put("iv", R.drawable.i8);
  •                 list.add(map);
  •                 return list;
  •         }
  • }

运行结果:
file:///F:/%E7%AC%94%E8%AE%B0/temp/7c3314e7-e831-4e98-9e52-0e671208da4b/4/index_files/cdfe70b3-870c-4a53-a16d-3b34fef97e63.jpg




[size=1.2] 其实SimpleAdapter与ArrayAdapter不尽相同,如果要显示复制样式的ListView时,需要用集合来添加数据
[size=1.4]ListView之BaseAdapter(推荐)

优点:适应任何数据的适配
1,定义ListView属性(省略了咯)
2,具体代码(无优化的也省略了咯,)
  • public class MainActivity extends Activity {
  •         private List<Map<String, Object>> data;
  •         @Override
  •         protected void onCreate(Bundle savedInstanceState) {
  •                 super.onCreate(savedInstanceState);
  •                 setContentView(R.layout.activity_main);
  •                 data=getData();
  •                 ListView lv = (ListView) findViewById(R.id.lv);
  •                 lv.setAdapter(new MyAdapter());
  •         }
  •         private List<Map<String, Object>> getData() {
  •         //创建List集合存储整个数据
  •                 List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();               
  •         //创建Map集合对象,通过Key存储对应的Value,
  •         Map<String, Object> map = new HashMap<String, Object>();
  •                 map.put("tv", "一");
  •                 map.put("iv", R.drawable.i1);
  •                 list.add(map);
  •                 map = new HashMap<String, Object>();
  •                 map.put("tv", "二");
  •                 map.put("iv", R.drawable.i2);
  •                 list.add(map);
  •                 map = new HashMap<String, Object>();
  •                 map.put("tv", "三");
  •                 map.put("iv", R.drawable.i3);
  •                 list.add(map);
  •                 map = new HashMap<String, Object>();
  •                 map.put("tv", "四");
  •                 map.put("iv", R.drawable.i4);
  •                 list.add(map);
  •                 map = new HashMap<String, Object>();
  •                 map.put("tv", "五");
  •                 map.put("iv", R.drawable.i5);
  •                 list.add(map);
  •                 map = new HashMap<String, Object>();
  •                 map.put("tv", "六");
  •                 map.put("iv", R.drawable.i6);
  •                 list.add(map);
  •                 map = new HashMap<String, Object>();
  •                 map.put("tv", "七");
  •                 map.put("iv", R.drawable.i7);
  •                 list.add(map);
  •                 map = new HashMap<String, Object>();
  •                 map.put("tv", "八");
  •                 map.put("iv", R.drawable.i8);
  •                 list.add(map);
  •                 map = new HashMap<String, Object>();
  •                 map.put("tv", "九");
  •                 map.put("iv", R.drawable.i9);
  •                 list.add(map);
  •                 map = new HashMap<String, Object>();
  •                 map.put("tv", "十");
  •                 map.put("iv", R.drawable.i10);
  •                 list.add(map);
  •                 return list;
  •         }
  •         public class MyAdapter extends BaseAdapter {
  •         //获取数据的长度,从而决定要显示的行数
  •                 @Override
  •                 public int getCount() {
  •         //在实际开发中,此处的返回值是由数据库中查询出来的总条数
  •                         return data.size();
  •                 }
  •         //根据ListView所在位置返回View
  •                 @Override
  •                 public Object getItem(int position) {
  •                         return null;
  •                 }
  •         //根据ListView位置得到数据源集合中的If
  •                 @Override
  •                 public long getItemId(int position) {
  •                         return 0;
  •                 }
  •         //重点在此,此方法觉得listview的界面样式
  •                 @Override
  •                 public View getView(int position, View convertView, ViewGroup parent) {
  •                         View view;
  •                         if (convertView == null) {
  •                                 view = LayoutInflater.from(getApplicationContext()).inflate(
  •                                                 R.layout.item, null);
  •                         } else {
  •                                 view = convertView;
  •                         }
  •             //初始化控件,并绑定数据,由于控件是在容器的item界面中,需要通过view对象调用,不然会造成空指针异常
  •                         ImageView iv = (ImageView) view.findViewById(R.id.iv);
  •                         TextView tv = (TextView) view.findViewById(R.id.tv);
  •                         iv.setBackgroundResource( (Integer) data.get(position).get("iv"));
  •                         tv.setText((CharSequence) data.get(position).get("tv"));
  •                         return view;
  •                 }
  •         }







ListView优化一    通过缓存convertView,这种利用缓存contentView的方式可以判断如果缓存中不存在View才创建View,如果已经存在可以利用缓存中的View,提升了性能
  •                 @Override
  •                 public View getView(int position, View convertView, ViewGroup parent) {
  •                         View view;
  •                         if (convertView == null) {
  •                  //将xml文件打包成界面显示出来
  •                                 view = LayoutInflater.from(getApplicationContext()).inflate(
  •                                                 R.layout.item, null);
  •                         } else {
  •                                 view = convertView;
  •                         }
  •                         ImageView iv = (ImageView) view.findViewById(R.id.iv);
  •                         TextView tv = (TextView) view.findViewById(R.id.tv);
  •                         iv.setBackgroundResource( (Integer) data.get(position).get("iv"));
  •                         tv.setText((CharSequence) data.get(position).get("tv"));
  •                         return view;
  •                 }




file:///F:/%E7%AC%94%E8%AE%B0/temp/7c3314e7-e831-4e98-9e52-0e671208da4b/4/index_files/fca106dc-ca6f-4565-a210-b910a1f567c5.jpg

ListView优化二(最优)   通过convertView+ViewHolder来实现,ViewHolder就是一个静态类,使用 ViewHolder 的关键好处是缓存了显示数据的视图(View),加快了 UI 的响应速度。
   当我们判断 convertView == null  的时候,如果为空,就会根据设计好的List的Item布局(XML),来为convertView赋值,并生成一个viewHolder来绑定converView里面的各个View控件(XML布局里面的那些控件)。再用convertView的setTag将viewHolder设置到Tag中,以便系统第二次绘制ListView时从Tag中取出。

   
  •                 @Override
  •                 public View getView(int position, View convertView, ViewGroup parent) {
  •                         ViewHolder viewHolder;
  •                         if (convertView == null) {
  •                                 viewHolder = new ViewHolder();
  •                                 convertView = mInflater.inflate(R.layout.item, null);
  •                                 viewHolder.iv = (ImageView) convertView.findViewById(R.id.iv);
  •                                 viewHolder.tv = (TextView) convertView.findViewById(R.id.tv);
  •                                 convertView.setTag(viewHolder);
  •                         } else {
  •                                 viewHolder = (ViewHolder) convertView.getTag();
  •                         }
  •                         viewHolder.iv.setImageResource((Integer) data.get(position).get(
  •                                         "iv"));
  •                         viewHolder.tv.setText((CharSequence) data.get(position).get("tv"));
  •                         return convertView;
  •                 }






ListView点击事件的简单实现
  • lv.setOnItemClickListener(new OnItemClickListener() {
  •                 @Override
  •                 public void onItemClick(AdapterView<?> parent, View view,
  •                                 int position, long id) {
  •             //获取点击条目对象
  •                         Fruit fruit = fruitList.get(position);
  •                         Toast.makeText(getApplicationContext(), fruit.getName(),
  •                                         Toast.LENGTH_SHORT).show();
  •                 }
  •         });





总结:1.BaseAdapter(优先原则)
因为是最基本的适配器,个人认为最优化原则下,它能实现如ListView,GridView,Gallery,Spinner等众多布局.BaseAdapter直接继承接口类Adapter.
关键在与它有具体的优化,能狗极大提高效率,节约内存,至于优化一还是优化二,其实在笔者看来两者都可选.


2.掌握基础的用法
组合就五花八门了,关键在于数据与适配器的选择,如果只是简单的数组显示,任意选择都行,但是如果涉及到复杂显示,建议使用BaseAdapter或ArrayAdapter来提高效率,

3.getView的优化不仅仅能用于BaseAdapter,也能用于ArrayAdapter,

4.Android中Adapter类其实就是把数据源绑定到指定的View上,然后再返回该View,而返回来的这个View就是ListView中的某一行item。这里返回来的View正是由我们的Adapter中的getView方法返回的。这样就会容易理解数据是怎样一条一条显示在ListView中的

5.最后给一些自问
    问题1:为什么要重写一个adapter?

    问题2:究竟该继承那个Adapter?

    问题3:定义适配器是定义内部类还是工具类?

    问题4:理解应用中的数据源一般都会用到Map类型的List有什么用?

    问题5:adapter是怎样把数据一条条的item展示到ListView上的?

    问题6:重写的方法中各有什么用途?

    问题7:自己到底掌握没?




免费评分

参与人数 3热心值 +3 收起 理由
AWEIWEI + 1 鼓励转贴优秀软件安全工具和文档!
帅的谁爱 + 1 鼓励转贴优秀软件安全工具和文档!
Sound + 1 鼓励转贴优秀软件安全工具和文档!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| awareness 发表于 2016-9-22 22:39
lan2602144404 发表于 2016-9-22 21:25
这个是干什么的,谢谢分享

....这个你都不知道就来谢谢分享了我是真心的佩服你
这个是android的列表显示.
在android基础中是个难点和重点,主要是适配器的使用让初学者很容易打迷糊,前几天看一个培训机构的讲的时候觉得讲太差,所以想把它总结一下咯
 楼主| awareness 发表于 2016-9-24 13:30
真爱贤 发表于 2016-9-23 09:14
还在用listview???recyclerView表示不服,官方已经不推介使用listview了!!!

官方并没有不推荐使用listview,就目前而言listView仍旧可以应付大多数场景,
而且ItemDecoration从实现来讲,官方目前并没有提供默认的实现类,所以这里就需要你加油
Dirge 发表于 2016-9-22 19:14
Sound 发表于 2016-9-22 19:15

温故而知新,看了后 又多了些感触。
qwe5219004 发表于 2016-9-22 19:24

很好很强大 支持了
 楼主| awareness 发表于 2016-9-22 19:44
Sound 发表于 2016-9-22 19:15
温故而知新,看了后 又多了些感触。

哈哈哈哈,谢谢谢谢
lan2602144404 发表于 2016-9-22 21:25
这个是干什么的,谢谢分享
lan2602144404 发表于 2016-9-23 07:28
awareness 发表于 2016-9-22 22:39
....这个你都不知道就来谢谢分享了我是真心的佩服你
这个是android的列表显示.
在android基础中是个难 ...

不懂用才会问呀,不说谢谢分享说什么呢?
夙杀々冷封 发表于 2016-9-23 08:33
楼主辛苦了
真爱贤 发表于 2016-9-23 09:14
还在用listview???recyclerView表示不服,官方已经不推介使用listview了!!!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-15 08:30

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表