ListView是Android开发中比较常用的一个组件,它以列表的形式展示信息,并能根据信息的长度自适应显示。比如说我们手机里的通讯录就用到了ListView显示联系人信息。在大量的场合下,我们都需要使用这个控件。虽然在Android 5.0时代,RecyclerView在很多地方都在逐渐取代ListView,但ListView的使用范围依然非常的广泛。我们也不能跳过ListView直接去学习RecyclerView,对ListView的透彻理解是十分有必要的。
首先来看ListView在View树中所处的位置:
ListView的官方解释:
A view that shows items in a vertically scrolling list.
The items come from the {@link ListAdapter} associated with this view.
即:一种在垂直滚动列表中显示项目的视图。
显示的项目(数据)通过ListAdapter适配器来与视图关联。
数据适配器是连接数据源和视图界面的桥梁,它用来把复杂的数据(数组、链表、数据库、集合等)填充在指定视图界面上。数据适配器的实现过程为:1.新建适配器–>2.添加数据源到适配器–>3.视图加载适配器。
那么ListAdapter是什么适配器呢?Adapter是所有适配器的祖先接口,下图为ListAdapter在所有适配器继承树中的位置:
自定义数据适配器的时候用到了BaseAdapter类,那么ListAdapter和BaseAdapter是什么关系呢?只看名字好像BaseAdapter是ListAdapter的长辈,但实际上ListAdapter是所有可以用于ListView的适配器的祖先,且仅仅为一个接口。下面为ListAdapter的继承树:
这样,显示的项目(数据)通过ListAdapter适配器来与视图关联这句话的含义便很易理解了,不管是ArrayAdapter、SimpleAdapter、SimpleCursorAdapter或者自定义BaseAdapter,只要这些适配器实现了ListAdapter接口,就可以统称为ListAdapter适配器,继而用于ListView的数据适配,下面为展开的继承树:
这下我们就不用去询问别人ListView有哪几种适配器了,我们已经自己推导出上图除红锁标记的私有类外的其他适配器都可以给ListView用。下面来看比较常用的四种适配器:ArrayAdapter、SimpleAdapter、SimpleCursorAdapter以及自定义BaseAdapter。
ArrayAdapter(数组适配器)
用于绑定格式单一的数据,数据源可以是集合或数组。
布局文件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
RelativeLayout>
MainActivity.java 如下:
package com.example.listview;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Adapter;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.SimpleCursorAdapter;
public class MainActivity extends AppCompatActivity {
private ListView mListView;
private ArrayAdapter arrayAdapter;
private String[] data = new String[]{"熊大", "熊二", "跳跳","熊大", "熊二", "跳跳",
"熊大", "熊二", "跳跳","熊大", "熊二", "跳跳"};//数据源
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (ListView) findViewById(R.id.listView);
//1.新建数据适配器 2.添加数据源到适配器
arrayAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, data);
//3.视图加载适配器
mListView.setAdapter(arrayAdapter);
}
}
到这里对ArrayAdapter的一个简单示例就完成了,那对ArrayAdapter的学习到这就可以结束了吗?可以跳到SimpleAdapter的学习了吗?本来是这么打算的,毕竟最常用的是自定义BaseAdapter数据适配器,ArrayAdapter了解一下就可以了啦。可是…可是我看到了这个:
记得面试官问我缺点的时候我说我的缺点是不求甚解的反面,导致学习进度很慢…BaseAdapter万能适配器什么鬼的你们在后边等着我吧…我们接着来看ArrayAdapter……
上面示例新建数据适配器的方式是上图中的第三种创建方式,要掌握其他创建方式,先要了解参数含义:
context : 当前上下文
resource : item的布局文件
textViewResourceId : item布局文件中的TextView的ID (可不指定)
objects : 数据源 (可不指定)
如果参数resource设置为只含有一个TextView控件(可为TextView衍生出的控件如CheckedTextView)的布局文件,则可不指定textViewResourceId参数,比如上面示例中的android.R.layout.simple_list_item_1就是一个TextView,Item内容直接显示在resource布局中,也就是TextView中。
如果参数resource没有设置成仅含有一个TextView的布局文件,则必须在这个布局文件中包含一个TextView,且必须设置参数textViewResourceId指定其中的TextView的ID。此时Item就不再只是单调的TextView布局,而可以在resource指定的布局文件中自定义。但数据只能显示在其中的TextView中,示例如下:
Item布局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:id="@+id/within_textview"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
LinearLayout>
LinearLayout>
新建适配器代码修改为下:
arrayAdapter = new ArrayAdapter(this, R.layout.item,R.id.textView,data);
看来一开始对ArrayAdapter的定义还是挺准确的:用于绑定格式单一的数据,数据源可以是集合或数组。格式单一的是数据,布局可以自己定义,但是数据只能在一个TextView上显示。这种也可以记作样式丰富但内容简单的,而第一个示例可以记作样式和内容都简单的。如果我们需要展示的内容是仅一个textview承载不了的,还需要其它组件,怎么办?那么有没有一个方法可以实现样式和内容都是丰富的呢?有,但是原生的ArrayAdapter无法实现这个功能,需要自定义一个ArrayAdapter类并重写getView()方法才能实现。
丰富的内容通过User类来实现:
package com.example.listview;
/**
* Created by yinghao on 2016/6/10.
*/
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
丰富的布局通过自定义item布局文件来实现:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:id="@+id/within_textview"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tv_age"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
LinearLayout>
将丰富的内容显示在丰富的控件上通过自定义ArrayAdapter类来实现:
package com.example.listview;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.TextView;
/**
* Created by yinghao on 2016/6/10.
*/
public class MyArrayAdapter extends ArrayAdapter<User> {
private int resourceId;
public MyArrayAdapter(Context context, int resource, User[] objects) {
super(context, resource, objects);
this.resourceId = resource;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
User user = getItem(position);
LinearLayout userListItem = new LinearLayout(getContext());
String inflater = Context.LAYOUT_INFLATER_SERVICE;
LayoutInflater vi = (LayoutInflater)getContext().getSystemService(inflater);
vi.inflate(resourceId, userListItem, true);
TextView name = (TextView) userListItem.findViewById(R.id.tv_name);
TextView age = (TextView) userListItem.findViewById(R.id.tv_age);
name.setText(user.getName());
age.setText(String.valueOf(user.getAge()));
return userListItem;
}
}
MainActivity.java 文件代码如下:
package com.example.listview;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;
public class MainActivity extends AppCompatActivity {
private ListView mListView;
private User[] users = new User[10];//数据源
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//准备数据源
for (int i = 0;i<10;i++) {
User user = new User("name"+i,15+i);
users[i] = user;
}
mListView = (ListView) findViewById(R.id.listView);
//1.新建数据适配器 // 2.添加数据源到适配器
MyArrayAdapter arrayAdapter = new MyArrayAdapter(this, R.layout.item, users);
//3.视图加载适配器
mListView.setAdapter(arrayAdapter);
}
}
显示结果如下:
总结:以上学习了ListView与listAdapter适配器的概念及其关系,然后演绎了ArrayAdapter的三种实现方式,分别是样式和内容都是简单的、样式丰富但内容简单的、样式和内容都丰富的三种。其中前两种用原生的ArrayAdapter就可以实现,通过对原生ArrayAdapter几种构造方法的研究得出了数据只能显示在TextView上的结论;第三种方式需要自己重写getView()方法,在一定程度上也可以算作自定义Adapter。另外对于绑定的数据可以为格式单一的泛型的数组或集合,上面涉及到的为String数组和User数组,也可以为List集合。
关于ArrayAdapter先学到这,接下来学习SimpleAdapter、SimpleCursorAdapter以及自定义BaseAdapter…