一、适配器视图与适配器AdapterView& Adapter
适配器视图AdapterView继承自视图组ViewGroup (一个包含其他子视图的容器),它是需要适配器的视图容器,常用的适配器视图有 Spinner、ListView、GridView、Gallery、ViewPager。
适配器视图是一种特殊类型的视图组。与其他的视图组类型一样,适配器视图的主要用途是表示一个包含子视图的视图。因此,适配器视图确定了其子视图布局的表现形式。此外,它还在关系中扮演了其他一些特殊角色:适配器视图控制屏幕上所显示的项目数量:这是一个非常关键的认识。虽然适配器对需要显示的数据绑定视图的移交进行控制,但却由适配器视图来告诉适配器应该生成多少视图。这一点在数据绑定过程中至关重要,因为它可以考虑到各种屏幕大小,同时帮助内存管理。后面将介绍更多这方面的内容。
适配器视图包含对项目选择响应事件,以及请求绑定数据实体的机制:当使用适配器视图时,可以根据用户交互简单地构建响应布局。此外,还可以非常容易地访问相应的数据项,而不必通过极端方法来查找原始数据项。
适配器视图可以支持使其子视图具有动画效果的逻辑:当使用诸如垂直或者水平滚动列表之类的控件时,如果可以引入一些平滑的动画效果那就更好了,这样可以改善用户的体验。可从ViewGroup类中继承该操作。
适配器在视图与数据之间扮演了一个桥梁的作用,它将数据中的每一项数据转化为适配器视图可以使用的每一个视图项。
适配器视图与适配器—类图:
该图中,左侧类图是关于适配器Adapter的,可以看到BaseAdapter抽象类实现了ListAdapter和SpinnerAdapter这两个接口,在我们自定义的适配器中,就是要继承BaseAdapter这个类。右侧类图是关于适配器视图AdapterView的,最下面的那四个具体类Spinner、Gallery、ListView、GridView就是常用的适配器视图。
下面讲解几个实例,练习使用Spinner和ListView适配器视图。
Spinner (下拉列表)有两种定义方式
- 使用静态资源
使用资源文件中的字符串数组,数据是固定的;
这是最常用、最简单的方式。
2.使用适配器
使用数组适配器(ArrayAdapter),数据长度可变。
二、实例--Spinner使用静态资源
1.在 strings.xml 中定义字符串数据,用作静态资源。
2.可以在 Java 中使用以下方法获得资源中的数组数据
String[] skills =getResources().getStringArray(R.array.skills);
3.在布局文件中,定义Spinner适配器视图,并引用字符串静态资源:
4.逻辑部分的实现:
在主活动Java代码中,通过id获取到XML布局文件定义的Spinner适配器视图控件,并给它设置下拉列表项被选择监听事件,spinner.setOnItemSelectedListener(),将用户选择的下拉选项,显示在一个TextView上。
三、实例--Spinner使用适配器
在主活动.java文件中,先声明适配器视图Spinner、数据和适配器,创建好适配器,并给Spinner设置适配器,适配器将视图和数据一项一项的联系起来。上图可见,数据是一个ArrayList,此次数据是可以变化的,初始化的时候,给它add()了几个数据,设置该数据可以从网络上获得。
XML布局文件--显示效果如图:
实现功能:从下拉列表中,可以删除选中的项,也可以增加新项。
(1)XML布局文件:activity_spinner2.xml
<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"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="专业技能"
android:id="@+id/textView"
android:layout_alignParentTop="true"
android:layout_alignBottom="@+id/spinner"
android:gravity="center_vertical"
android:layout_marginRight="16dp"/>
<Spinner
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/spinner"
android:layout_alignParentTop="true"
android:layout_toRightOf="@+id/button_remove"
android:layout_toEndOf="@+id/button_remove"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="删除选中项"
android:id="@+id/button_remove"
android:layout_below="@+id/spinner"
android:onClick="doRemove"/>
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/editText"
android:singleLine="true"
android:hint="已掌握的的技能"
android:layout_below="@+id/button_remove"
android:layout_toRightOf="@+id/button_add"
android:layout_toEndOf="@+id/button_add"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="添加新选项"
android:id="@+id/button_add"
android:layout_alignBottom="@+id/editText"
android:onClick="doAdd"/>
</RelativeLayout>
(2)活动类文件Spinner2Activity.java
package com.example.administrator.adapterdemo; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.Spinner; import android.widget.Toast; import java.util.ArrayList; /** * 使用Spinner适配器视图 * 动态进行数据的处理操作 */ public class Spinner2Activity extends AppCompatActivity { // 视图 private Spinner spinner; // 数据 private ArrayList<String> data; // 适配器:视图与数据之间的桥 private ArrayAdapter<String> adapter; private EditText editText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_spinner2); spinner = (Spinner) findViewById(R.id.spinner); editText = (EditText) findViewById(R.id.editText); initView();//初始化 } private void initView() { // 初始化数据:可以数据源或网络获取 data = new ArrayList<>(); data.add("Android"); data.add("iOS"); data.add("Java"); data.add("C++"); // 参数一:上下文(Context) // 参数二:系统中的布局资源 android.R.layout.simple_spinner_dropdown_item // 参数三:数据,可以是字符串数据【长度不可变】,也可以是 ArrayList【长度可变】 adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item, data); // 将适配器设置为视图 spinner.setAdapter(adapter); } /** * 从 Spinner 中删除一项 * * @param v button_remove */ public void doRemove(View v) { // 获得选中项的位置;若无,则返回 -1 int position = spinner.getSelectedItemPosition(); if (-1 == position) { Toast.makeText(this, "无选中项", Toast.LENGTH_SHORT).show(); } else { // 从数据中删除当前选中项 data.remove(position); // 适配器通知【视图】数据集已改变,视图会重绘 adapter.notifyDataSetChanged(); } } /** * 在 Spinner 中新增一项 * * @param v button_add */ public void doAdd(View v) { // 获得输入内容 String input = editText.getText().toString(); if (input.equals("")) { return; //防止添加“空行” } editText.setText(""); // 在数据中添加新内容 data.add(input); // 获得列表的适配器中数据项的总数 int size = spinner.getAdapter().getCount(); //size = data.size(); // 设置选中选的位置 spinner.setSelection(size - 1); } }
四、ListView实例
1.ListView列表视图:
由多行构成
每行一个视图项
行数由数据决定
可单选、多选
是最常用的适配器视图
2.ListView设置选择模式(setChoiceMode)
模式 |
描述 |
CHOICE_MODE_NONE |
普通模式 |
CHOICE_MODE_SINGLE |
单选模式 |
CHOICE_MODE_MULTIPLE |
多选模式 |
CHOICE_MODE_MULTIPLE_MODAL |
Contextual ActionBar(CAB) 长按进入的多选模式 (暂不使用,具体见菜单章节) |
3.系统布局模版
系统提供的布局模版文件 |
描述 |
android.R.layout.simple_list_item_1 |
包含一个控件(TextView) android.R.id.text1 |
android.R.layout.simple_list_item_2 |
包含两个控件(TextView) android.R.id.text1 android.R.id.text2 |
android.R.layout.simple_list_item_activated_1 |
包含一个控件,可激活(高亮显示)的模版 |
android.R.layout.simple_list_item_checked |
可选择(单选、多选均可) |
android.R.layout.simple_list_item_single_choice |
可单选(RadioButton) |
android.R.layout.simple_list_item_multiple_choice |
可多选(CheckBox) |
4.实例功能
(1)实现如图“联系人”显示。
XML布局文件代码: activity_list_view2.xml
<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" tools:context=".MainActivity"> <ListView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/listView" android:layout_alignParentTop="true" android:layout_above="@+id/button" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="选中的内容" android:id="@+id/button" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:onClick="doClick"/> </RelativeLayout>
(2)活动类—代码:ListView2Activity.java
package com.example.administrator.adapterdemo; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.SparseBooleanArray; import android.view.View; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.Toast; import java.util.ArrayList; import java.util.HashMap; public class ListView2Activity extends AppCompatActivity { // 数据的标签(KEY) private static final String KEY_NAME = "name"; private static final String KEY_PHONE = "phone"; // 视图 private ListView listView; // 数据:由键值对构成的列表【供简单适配器使用】 private ArrayList<HashMap<String, Object>> data; // 适配器:简单适配器【一行可以显示多个控件】 private SimpleAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_list_view2); listView = (ListView) findViewById(R.id.listView); initView();//初始化 } private void initView() { // 初始化数据 data = new ArrayList<>(); for (int i = 0; i < 30; i++) { HashMap<String, Object> item = new HashMap<String, Object>(); item.put(KEY_NAME, "联系人 " + i); item.put(KEY_PHONE, "号码 " + i); data.add(item); } // 数据的 KEY 构成的数组 String[] from = {KEY_NAME, KEY_PHONE}; // 控件的 ID 构成的数组 int[] to = {android.R.id.text1, android.R.id.text2}; // 参数一:上下文 // 参数二:数据 // 参数三:系统布局模版【activated 代表可高亮显示,2 代表有两个控件】 // 参数四:数据的 KEY 构成的数组 // 参数五:控件的 ID 构成的数组 adapter = new SimpleAdapter( getApplicationContext(), data, android.R.layout.simple_list_item_activated_2, from, to); // 设置为多选模式 listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); // 设置适配器 listView.setAdapter(adapter); } /** * 显示选中内容 * * @param v button */ public void doClick(View v) { // 获得选中项的总数 int count = listView.getCheckedItemCount(); // 获得选中项的标识【使用SQLite及游标时可用】 long[] ids = listView.getCheckedItemIds(); // 获得选中的位置【单选】 int position = listView.getCheckedItemPosition(); // 获得选中的位置【多选,获得一个稀疏矩阵】 SparseBooleanArray array = listView.getCheckedItemPositions(); // 显示结果 Toast.makeText(this, array.toString(), Toast.LENGTH_SHORT).show(); } }
完整工程:https://github.com/ljheee/AdapterDemo
工程名AdapterDemo,工程下有4个活动(Activity),启动运行主活动,演示Spinner使用静态数据;主活动界面下有三个Button,点击可实现向其他活动的跳转。左下角Button跳转到Spinner2Activity演示Spinner动态处理数据;中间是演示简单ListView的使用;右下角跳转到最后一个ListView的演示。