Android基础控件之ListView详细使用讲解
来源:互联网 发布:编程语言的种类 编辑:程序博客网 时间:2024/05/30 04:54
前文
ListView作为Android最常用的控件之一,同时也是最难的控件之一,其难点主要在意用法的多变性,因此让众多的初学者都比较难掌握,包括我自己,也是在反复需要使用时,总会卡住.而在网上找了众多的ListView的实例,案例等,讲解得不尽人意,甚至让许多初学者有迷惑.所以才觉得写此文,将包括ListView的用法,具体的注解,详解以及方案,希望能帮到需要的人,若有不正之处还请指正,谢谢
由于ListView有指定的外观形式的,在此就不会使用那些
ListView显示数据的原理
注意事项:使用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”
属性没有添加android:footerDividersEnabled=”false” android:headerDividersEnabled=”false”
由于没有设置ListView的样式没有设置内边距,所以第一条目看不出是否有分隔条
ListView之ArrayAdapter
1,定义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.运行结果
ListView之SimpleAdapter
1,可以将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; }}
运行结果:
其实SimpleAdapter与ArrayAdapter不尽相同,如果要显示复制样式的ListView时,需要用集合来添加数据
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; }
ListView优化二(最优)
通过convertView+ViewHolder来实现,ViewHolder就是一个静态类,使用 ViewHolder 的关键好处是缓存了显示数据的视图(View),加快了 UI 的响应速度。
当我们判断 convertView == null 的时候,如果为空,就会根据设计好的List的Item布局(XML),来为convertView赋值,并生成一个viewHolder来绑定converView里面的各个View控件(XML布局里面的那些控件)。再用convertView的setTag将viewHolder设置到Tag中,以便系统第二次绘制ListView时从Tag中取出。
简单来讲,就是优化findViewById,按照优化一来讲,每次都需要初始化控件,都会消耗资源和时间,因此这里的优化就是将期进行封装
@Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder;//创建一个tag //1,如果convertView为空,就需要查找控件 if (convertView == null) { //2,初始化对象,存储在此期间找到的控件对象,通过convertView进行存储 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);//存储tag } else { //3,如果convertView不为空的时候直接获取控件,实现复用 viewHolder = (ViewHolder) convertView.getTag(); } viewHolder.iv.setImageResource((Integer) data.get(position).get( "iv")); viewHolder.tv.setText((CharSequence) data.get(position).get("tv")); return convertView; } // 复用viewHolder步骤二 static class ViewHolder { ImageViewiv; TextView tv ; }
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:自己到底掌握没?
6,若有雷同,纯属误会;若有错误,敬请指正
- Android基础控件之ListView详细使用讲解
- Android基础 | 控件基础 | Listview之SimpleAdapter
- Android基础控件讲解
- Android基础控件 - ListView
- Android基础之自定义控件、布局以及ListView控件
- Android之旅八 ListView、TabHost、Spinner控件详细介绍
- Android之ListView控件使用简单介绍
- Android 控件之ListView 的简单使用
- 【android基础学习之二】——基础控件ListView
- Android基础 | 控件基础 | Listview之BaseAdapter①
- Android基础 | 控件基础 | Listview之BaseAdapter②
- Android开发笔记:Android控件之listview基础篇
- Android基础之ListView的使用详解
- Android基础之ListView的使用详解
- Android 控件之ListView
- Android控件之ListView
- Android控件之ListView
- android控件之ListView
- 5.17
- 关于vfp6.0无法导入excel的问题解决
- 华硕笔记本nvidia显示设置不可用?
- 如何通过 bin setTitleEdgeInsets setImageEdgeInsets改变图片和文字的位置
- BZOJ 1009: [HNOI2008]GT考试【KMP上DP+矩阵快速幂
- Android基础控件之ListView详细使用讲解
- 自定义myScrollview
- javascript实现拖拽的原理
- C语言DAY11 - 指针patr1
- 判断是否有网
- 返回数组类型
- [Coursera 数字图像和视频处理基础 第二周]Signals and Systems
- 行人检测之DPM
- Java对象序列化