Android 自定义 Adapter

在上一章节中我们知道了啥是 Adapter,也知道了 Adapter 的家族体系,也用过了几个 XxxAdapter

本章节,我们就来自己实现一个 Adapter

Adapter 要实现的方法很多,我们并不打算从头定义,而是继承 BaseAdapter 然后重写几个方法

首先,我们要做的就是要了解我们到底要重写哪些方法,因为 BaseAdapter 实现了 ListAdapterSpinnerAdapter 接口,而这两个接口又继承自 Adapter

所以,我们先来看看接口 Adapter 有几个方法

Adapter 接口

打开 Adapter API 文档,我们可以看到它有以下几个方法要实现

方法 说明
int getCount() 数据集中有多少项目
Object getItem(int position) 获取与数据集中指定位置关联的数据项
long getItemId(int position) 获取与列表中指定位置关联的行 ID
int getItemViewType(int position) 获取将由 getView(int, View, ViewGroup)指定项目创建的视图类型
View getView(int position, View convertView, ViewGroup parent) 获取显示数据集中指定位置的数据的视图
int getViewTypeCount() 返回将由其创建的视图类型的数量 getView(int, View, ViewGroup)
boolean hasStableIds() 项目 id 在基础数据更改期间是否稳定
boolean isEmpty() 是否为空
void registerDataSetObserver(DataSetObserver observer) 注册一个在此适配器使用的数据发生更改时调用的观察者
unregisterDataSetObserver(DataSetObserver observer) 取消注册先前已通过此适配器注册的观察者 registerDataSetObserver(DataSetObserver)

方法说明简单明了,主要就是获取数据项的数量和获取数据项,获取数据项的类型和视图

SpinnerAdapter

只有一个公开方法

方法 说明
View getDropDownView(int position, View convertView, ViewGroup parent) 根据下拉式弹出窗口中显示数据集中指定的位置获取数据的视图

ListAdapter

只有两个方法

方法 说明
boolean areAllItemsEnabled() 设置是否启用此适配器中的所有项目
boolean isEnabled(int position) 判断指定位置上的项目是否启用

好了,简单明了,也没几个方法,我们再来看看 BaseAdapter

BaseAdapter

方法 说明
boolean areAllItemsEnabled() 判断是否启用此适配器中的所有项目
CharSequence[] getAutofillOptions() 获取可帮助 AutofillService 自动填充适配器支持的视图的适配器数据的字符串表示形式
View getDropDownView(int position, View convertView, ViewGroup parent) 根据下拉式弹出窗口中显示数据集中指定的位置获取数据的视图
int getItemViewType(int position) 获取将由 getView(int, View, ViewGroup)指定项目创建的视图类型
View getView(int position, View convertView, ViewGroup parent) 获取显示数据集中指定位置的数据的视图
boolean hasStableIds() 项目 id 在基础数据更改期间是否稳定
boolean isEmpty() 是否为空
boolean isEnabled(int position) 判断指定位置上的项目是否启用
void notifyDataSetChanged() 通知附属的观察者,底层数据已被更改,任何反映数据集的视图都应该自行刷新
void notifyDataSetInvalidated() 通知所附的观察员,底层数据不再有效或可用
void setAutofillOptions(CharSequence... options) 设置返回的值 getAutofillOptions()
void registerDataSetObserver(DataSetObserver observer) 注册一个在此适配器使用的数据发生更改时调用的观察者
void registerDataSetObserver(DataSetObserver observer) 注册一个在此适配器使用的数据发生更改时调用的观察者
unregisterDataSetObserver(DataSetObserver observer) 取消注册先前已通过此适配器注册的观察者 registerDataSetObserver(DataSetObserver)

方法说明简单明了,主要就是获取数据项的数量和获取数据项,获取数据项的类型和视图

现在我们看看我们要重写哪些方法

  1. 首先和监听器相关的都不用重写,因为暂时用不着,于是去掉

    1. notifyDataSetChanged()
    2. notifyDataSetInvalidated()
    3. registerDataSetObserver(DataSetObserver observer)
    4. registerDataSetObserver(DataSetObserver observer)
  2. 自动填充 相关的也暂时用不着 (以后有机会介绍吧),于是去掉

    1. setAutofillOptions(CharSequence... options)
    2. getAutofillOptions()
  3. 有些方法可以有选择性的实现

    1. getDropDownView()
    2. areAllItemsEnabled()
    3. isEnabled()
    4. isEmpty()
    5. getItemViewType()
    6. getItemViewTypeCount()

好了,还剩下 4 个方法

方法 说明
View getView(int position, View convertView, ViewGroup parent) 获取显示数据集中指定位置的数据的视图
int getCount() 数据集中有多少项目
Object getItem(int position) 获取与数据集中指定位置关联的数据项
long getItemId(int position) 获取与列表中指定位置关联的行 ID

知道了要重写几个方法就好办了,现在我们拿 Android Adapter 适配器SimpleAdapter 的范例来实现自己的 YetAdapter

自定义 BaseAdapter

我们先来看看效果图

对的,跟那个范例长得一模一样

  1. 创建一个 空的 Android 项目 cn.twle.android.YetAdapter

  2. 下载 /static/i/android/it_language_icon.zip 解压并把所有的图片拖到 res/drawable 目录

  3. 修改 activity_main.xml 添加一个 ListView

    <?xml version="1.0" encoding="utf-8" ?>
    <LinearLayout 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"
        android:padding="8dp" 
        android:orientation="vertical" >
    
        <ListView
            android:id="@+id/listview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
    
  4. 定义列表中每一行的布局,在 res/layout 目录下新建一个文件 list_item.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="match_parent"
        android:orientation="horizontal">
    
        <!-- 定义一个用于显示头像的 ImageView -->
        <ImageView
            android:id="@+id/icon"
            android:layout_width="32dp"
            android:layout_height="32dp"
            android:baselineAlignBottom="true"
            android:paddingLeft="8dp" />
    
        <!-- 定义一个竖直方向的 LinearLayout,把 语言 与 简介 的文本框设置出来 -->
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
    
            <TextView
                android:id="@+id/name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingLeft="8dp"
                android:textColor="#1D1D1C"
                android:textSize="20sp" />
    
            <TextView
                android:id="@+id/desc"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingLeft="8px"
                android:textColor="#B4B4B9"
                android:textSize="14sp" />
    
        </LinearLayout>
    </LinearLayout>
    
  5. 创建一个 Bean ,在 MainActivity.java 同目录下创建一个类 YetLanguage.java

    package cn.twle.android.yetadapter;
    
    public class YetLanguage  {
    
        private String aName;
        private String aDesc;
        private int aIcon;
    
        public YetLanguage () {
        }
    
        public YetLanguage (String aName, String aDesc, int aIcon) {
            this.aName = aName;
            this.aDesc = aDesc;
            this.aIcon = aIcon;
        }
    
        public String getaName() {
            return aName;
        }
    
        public String getaDesc() {
            return aDesc;
        }
    
        public int getaIcon() {
            return aIcon;
        }
    
        public void setaName(String aName) {
            this.aName = aName;
        }
    
        public void setaDesc(String aSpeak) {
            this.aDesc = aDesc;
        }
    
        public void setaIcon(int aIcon) {
            this.aIcon = aIcon;
        }
    }
    
  6. MainActivity.java 同目录下创建一个适配器 YetAdapter 继承自 BaseAdapter

    package cn.twle.android.yetadapter;
    
    import android.content.Context;
    import android.widget.BaseAdapter;
    
    import android.widget.TextView;
    import android.widget.ImageView;
    
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.LayoutInflater;
    
    import java.util.LinkedList;
    
    public class YetAdapter extends BaseAdapter {
    
        private LinkedList<YetLanguage> mData;
        private Context mContext;
    
        public YetAdapter(LinkedList<YetLanguage> mData, Context mContext) {
    
            this.mData = mData;
            this.mContext = mContext;
        }
    
        @Override
        public int getCount() {
            return mData.size();
        }
    
        @Override
        public Object getItem(int position) {
            return null;
        }
    
        @Override
        public long getItemId(int position) {
            return position;
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
    
            convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item,parent,false);
    
            ImageView img_icon = (ImageView) convertView.findViewById(R.id.icon);
            TextView txt_aName = (TextView) convertView.findViewById(R.id.name);
            TextView txt_aDesc = (TextView) convertView.findViewById(R.id.desc);
    
            img_icon.setBackgroundResource(mData.get(position).getaIcon());
            txt_aName.setText(mData.get(position).getaName());
            txt_aDesc.setText(mData.get(position).getaDesc());
    
            return convertView;
        }
    }
    
  7. 修改 MainActivity.java

    package cn.twle.android.yetadapter;
    
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    
    import android.widget.ListView;
    
    import java.util.LinkedList;
    import java.util.List;
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            List<YetLanguage>  mData = new LinkedList<YetLanguage>();
    
            mData.add(new YetLanguage("Kotlin", "Kotlin 是运行在 Java 虚拟机上的静态语言,被称之为 Android 世界的 Swift", R.drawable.kotlin));
            mData.add(new YetLanguage("Scala", "Scala 是一门多范式(multi-paradigm)的编程语言", R.drawable.scala));
            mData.add(new YetLanguage("Swift", "Swift 是开发 Mac APP 和 iOS APP 的语言", R.drawable.swift));
            mData.add(new YetLanguage("TypeScript", "TypeScript 是一种由微软开发的自由和开源的编程语言", R.drawable.typescript));
    
            //创建一个 YetAdapter
    
            YetAdapter yetAdapter = new YetAdapter((LinkedList<YetLanguage>) mData,getApplicationContext());
    
            ListView listView = (ListView) findViewById(R.id.listview);
            listView.setAdapter(yetAdapter);
        }
    }
    

对,就这么简单

参考文档

  1. Android 官方 BaseAdapter

Android 基础教程

关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.