热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Android基础控件之ListView详细使用讲解

前文ListView作为Android最常用的控件之一,同时也是最难的控件之一,其难点主要在意用法的多变性,因此让众多的初学者都比较难掌握,包括我自己,也是在反复需要使用时,总会卡住.

前文

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
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



<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 adapter = new ArrayAdapter(
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 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 fruitList = new ArrayList();
@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> getData() {
List> list = new ArrayList>();
Map map = new HashMap();
map.put("iv", R.drawable.i1);
map.put("tv", "G1");
list.add(map);
map = new HashMap();
map.put("tv", "G2");
map.put("iv", R.drawable.i2);
list.add(map);
map = new HashMap();
map.put("tv", "G3");
map.put("iv", R.drawable.i3);
list.add(map);
map = new HashMap();
map.put("tv", "G3");
map.put("iv", R.drawable.i4);
list.add(map);
map = new HashMap();
map.put("tv", "G3");
map.put("iv", R.drawable.i5);
list.add(map);
map = new HashMap();
map.put("tv", "G3");
map.put("iv", R.drawable.i6);
list.add(map);
map = new HashMap();
map.put("tv", "G3");
map.put("iv", R.drawable.i7);
list.add(map);
map = new HashMap();
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,若有雷同,纯属误会;若有错误,敬请指正


推荐阅读
author-avatar
天眞啲笨尛孩
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有