Android学习笔记9 界面编程之AdapterView系列控件

自从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之前,我们先看下面这张图,展示了这个类的继承结构关系。

AdapterView类的继承结构

首先可以看到它是个抽象类,继承的是ViewGroup,说明它是视图组合,它的直接子类相对来说我们可能不太熟悉,但是间接子类中有很多熟悉的控件,比如ListView,GridView,Spinner等。从这几个间接子类的相似之处我们可以初步确定AdapterView的主要特征。

官网上对它的介绍十分简单,An AdapterView is a view whose children are determined by anAdapter,AdapterView是一个子视图由适配器Adapter来决定的View。

二、Adapter相关

从AdapterView的简介中,我们看到适配器Adater的重要性,那么它又是何方神圣呢,我们继续看下去。

接口Adapter继承结构图

可以看到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);
    }
}

说明:

  1. 布局文件比较简单,线性布局内,一个TextView+一个ListView
  2. 代码文件内,重点主要是在初始化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优化:

  1. 上面继承BaseAdapter实现自定义Adapter中,首先是构造函数传入上下文和数据集合,上下文主要是用于实例化LayoutInflater之后生成布局,之后是实现几个必要的方法,具体作用都已经有注释。
  2. 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

Demo主界面
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,681评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,710评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,623评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,202评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,232评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,368评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,795评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,461评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,647评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,476评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,525评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,226评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,785评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,857评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,090评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,647评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,215评论 2 341

推荐阅读更多精彩内容