自从RecyclerView出来之后,Android开发者们对它青睐有加。各种使用教程,各种开源库,一时间好像再用ListView就是落伍一样。诚然,Google推出的RecyclerView的确比原有的一些控件优秀很多,高度的解耦,灵活的布局,性能优化等方面,但是我觉得不管什么时候,在原有的经典控件的使用基础上再去学习新的控件比较好,对比新老控件的差异之处,也能更好地帮助我们了解这些控件的设计思想和相关原理。
这篇主要总结几个常用控件的基本使用,它们都是AdapterView的间接子类。文章最后给出了涉及到的控件的基本使用Demo,大家可以下载参考一下,有问题可以交流,共同学习。
一、AdapterView概述
二、Adapter相关
三、常见例子
1、ListView简单使用
2、ListView使用进阶
3、ExpandableListView概述
4、GridView概述
5、ListActivity概述
6、Spinner概述
7、RecyclerView概述
四、源码地址
一、AdapterView概述
在介绍AdapterView之前,我们先看下面这张图,展示了这个类的继承结构关系。
首先可以看到它是个抽象类,继承的是ViewGroup,说明它是视图组合,它的直接子类相对来说我们可能不太熟悉,但是间接子类中有很多熟悉的控件,比如ListView,GridView,Spinner等。从这几个间接子类的相似之处我们可以初步确定AdapterView的主要特征。
官网上对它的介绍十分简单,An AdapterView is a view whose children are determined by anAdapter,AdapterView是一个子视图由适配器Adapter来决定的View。
二、Adapter相关
从AdapterView的简介中,我们看到适配器Adater的重要性,那么它又是何方神圣呢,我们继续看下去。
可以看到Adapter是一个接口,它的子类有ArrayAdapter,BaseAdapter等等,ListView应该是日常开发中比较常用的控件了,通常我们会给它设置一个适配器ArrayAdapter或者自己实现的BaseAdapter来显示列表数据。
Adapter object acts as a bridge between anAdapterViewand the underlying data for that view. The Adapter provides access to the data items. The Adapter is also responsible for making aViewfor each item in the data set.
Adapter适配器充当着AdapterView和视图关联的数据的桥梁的作用。适配器Adapter提供数据项的访问,负责数据集合中每项视图的生成。
三、常见例子与解析
这一部分我主要是结合比较常用的例子来展示下AdapterView的几个子类结合数据适配器Adapter的使用。
1、ListView简单使用 ( ListView + ArrayAdapter )
效果主要如下图所示,界面很简单,主要是顶部一个TextView加上下面一个ListView,设置ArrayAdapter类型的适配器,提供数据。
1、布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:textSize="20sp"
android:text="学生名单"/>
<ListView
android:id="@+id/lv_students"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
2、代码文件
public class ListNormalActivity extends Activity {
private ListView mListView;
private String[] mData = new String[]{"王小明", "李小红", "张小雨", "毛小李", "华佗", "刘亦菲"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_activity_listnormal);
initListView();
}
private void initListView() {
mListView = (ListView) findViewById(R.id.lv_students);
ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
android.R.layout.simple_list_item_1,
mData);
mListView.setAdapter(adapter);
}
}
说明:
- 布局文件比较简单,线性布局内,一个TextView+一个ListView
- 代码文件内,重点主要是在初始化ArrayAdapter的时候,3个参数,第1个为上下文,第2个为列表项的布局资源,这个我们用系统自带的,它是一个简单的TextView,第3个为数据集合。
2、ListView使用进阶( ListView + BaseAdapter )
一般情况下在平时使用ListView时,列表的每一项的布局可能会相对复杂一点,需要自己新建继承自BaseAdapter的适配器,同时自己写布局。
1、首先我们准备一个学生的实体类,StuEntity 。
public class StuEntity {
//学生照片id
private int stuPhotoId;
//学生姓名
private String stuName;
//学生专业
private String stuMajor;
//构造函数
public StuEntity(int stuPhoto, String stuName, String stuMajor) {
this.stuPhotoId = stuPhoto;
this.stuName = stuName;
this.stuMajor = stuMajor;
}
public int getStuPhotoId() {
return stuPhotoId;
}
public void setStuPhotoId(int stuPhotoId) {
this.stuPhotoId = stuPhotoId;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public String getStuMajor() {
return stuMajor;
}
public void setStuMajor(String stuMajor) {
this.stuMajor = stuMajor;
}
}
2、因为ListView中每一项的布局是我们自定义的,所以先准备一个布局文件,这里先简单的用一个ImageView和两个TextView组成的布局view_item_stulist.xml作为演示。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="60dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_photo"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_margin="5dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="3"
android:gravity="center"
android:text="学生姓名"/>
<TextView
android:id="@+id/tv_major"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="2"
android:gravity="center"
android:text="学生专业"/>
</LinearLayout>
</LinearLayout>
3、之后是继承了BaseAdapter的自定义适配器,这里是关注的重点,也是ListView优化中比较重要的部分。
public class StuAdapter extends BaseAdapter {
//数据集合
private List<StuEntity> mData;
private LayoutInflater mInflater;
public StuAdapter(Context context, List<StuEntity> data) {
mData = data;
mInflater = LayoutInflater.from(context);
}
//返回数据集合的数量
@Override
public int getCount() {
return mData.size();
}
//返回指定位置的数据
@Override
public StuEntity getItem(int position) {
return mData.get(position);
}
//返回指定位置的数据项id
@Override
public long getItemId(int position) {
return position;
}
//生成视图
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
//如果没有可以复用的View
if (convertView == null) {
//通过LayoutInflater实例化布局
convertView = mInflater.inflate(R.layout.view_item_stulist, null);
holder = new ViewHolder();
holder.ivStuPhoto = (ImageView) convertView.findViewById(R.id.iv_photo);
holder.tvStuName = (TextView) convertView.findViewById(R.id.tv_name);
holder.tvStuMajor = (TextView) convertView.findViewById(R.id.tv_major);
convertView.setTag(holder);
} else {
//如果有可以复用的View 就通过tag找到缓存的布局
holder = (ViewHolder) convertView.getTag();
}
holder.ivStuPhoto.setImageResource(mData.get(position).getStuPhotoId());
holder.tvStuName.setText(mData.get(position).getStuName());
holder.tvStuMajor.setText(mData.get(position).getStuMajor());
return convertView;
}
//静态类
static class ViewHolder {
ImageView ivStuPhoto;
TextView tvStuName;
TextView tvStuMajor;
}
}
4、Activity的布局比较简单
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:text="学生名单"
android:textSize="20sp"/>
<ListView
android:id="@+id/lv_students"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
5、Activity里的代码
public class ListComActivity extends Activity {
//学生列表的ListView
private ListView mListView;
//学生列表的ListView的适配器
private StuAdapter mStuAdapter;
//学生列表的数据
private List<StuEntity> mData = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_activity_listcom);
initListView();
}
private void initListView() {
//模拟获取数据
getStuData();
mListView = (ListView) findViewById(R.id.lv_students);
//初始化适配器Adapter
mStuAdapter = new StuAdapter(ListComActivity.this, mData);
mListView.setAdapter(mStuAdapter);
}
private void getStuData() {
for (int i = 0; i < 20; i++) {
mData.add(new StuEntity(R.mipmap.ic_launcher, "王小明" + i, "计算机科学与技术" + i));
}
}
}
ListView优化:
- 上面继承BaseAdapter实现自定义Adapter中,首先是构造函数传入上下文和数据集合,上下文主要是用于实例化LayoutInflater之后生成布局,之后是实现几个必要的方法,具体作用都已经有注释。
- ListView常见优化技巧有:(1) 充分利用convertView,系统缓存的View来达到复用优化的目的。(2) 定义静态类ViewHolder来减少findViewById的使用,提高效率。(3) ListView在真正的使用过程中,还需控制每次数据的加载数量,做到分页加载等。
3、ExpandableListView概述
ExpandableListView是一个继承ListView的子类,大家可以打开QQ的联系人模块可以看到这个组件,点击每一个分组,会弹出一个二级列表,展示该分组内具体的QQ好友。使用ExpandableListView组件的关键就是设置它的adapter,这个adapter必须继承BaseExpandbaleListAdapter类,所以实现运用ExpandableListView的核心就是学会继承这个BaseExpanableListAdapter类。
4、ListActivity概述
ListActivity是一个不需要我们设置布局,设置一个数据适配器ArrayAdapter后即可直接在界面上显示一个列表集合的Activity,使用起来很方便。
5、Spinner概述
Spinner大家应该比较熟悉,当我们在进行用户注册填写资料时,有时某些信息会让我们在下拉列表里选择,里面的数据可以直接在静态布局里设置,也可以在代码里控制。
6、RecyclerView概述
RecyclerView是support-v7包中的新组件,是一个强大的滑动组件,与经典的ListView相比,同样拥有item回收复用的功能,但是直接把viewholder的实现封装起来,用户只要实现自己的viewholder就可以了,该组件会自动帮你回收复用每一个item。它不但变得更精简,也变得更加容易使用,而且更容易组合设计出自己需要的滑动布局。
四、源码地址
之前简单地把代码分享到百度云上,后来失效了,现在我把代码放到了码云oschina上,大家可以看看。
https://git.oschina.net/tanshicheng/DemoAdapterView.git