AdapterView的内容一般是包含多项相同格式资源的列表,本身是一个抽象基类,它派生的子类用法很相似,只是显示界面有些不同。
特征:
AdapterView继承自ViewGroup,本质是个容器
AdapterView可以包含多个“列表项”,并将这多个列表项以合适的形式展示
AdapterView显示的列表项内容由Adapter提供
它派生的子类在用法上也基本相似,只是在显示上有一定区别,因此把他们也归为一类。
由AdapterView直接派生的三个类:
AbsListView、AbsSpinner、AdapterViewAnimator
平常用的多的是上图中第四行以下的子类,需要注意的是Gallery是一个过时的API,可以使用HorizontalScrollView替代
ListView是一种使用非常广泛的组件,它以垂直列表的形式显示所有列表项。
有两种方式创建:
1.直接使用ListView控件进行创建,这种方式最常见
2.让Activity继承ListActivity,相当于让该Activity显示的组件为ListView
创建ListView后,接下来就要为ListView设置它将要显示的列表项了,可以通过android:entries属性设置一个资源文件上去,推荐的方法是通过setAdapter(Adapter)方法为之提供一个适配器,适配器提供列表项即可。
AbsListView常用的XML属性及相关方法
XML属性 | 相关方法 | 说明 |
---|---|---|
android:choiceMode | 设置AbsListView的选择行为: none:不显示任何选中项 singleChoice:允许单选 multipleChoice:允许多选 multipleChoiceModal:允许多选 |
|
android:drawSelectorOnTop | setDrawSelectorOnTop(boolean) | 如果设置该属性为true,选中的列表项将会显示在上面 |
android:fastScrollEnabled | 设置是否允许快速滚动,如果设置为true,将会显示滚动图标,并允许用户拖动该滚动图标进行快速滚动 | |
android:smoothScrollbar | setSmoothScrollbarEnabled(boolean) | 如果设置为true,列表会使用更精确的基于条目在屏幕上的可见像素高度的计算方法。 默认该属性为真,如果你的适配器需要绘制可变高的条目,他应该设为假。 当该属性为真时,你在适配器在显示变高条目时,滚动条的把手会在滚动的 过程中改变大小。当设为假时,列表只使用适配器中的条目数和屏幕上的 可见条目来决定滚动条的属性 |
android:stackFromBottom | 用于 ListView 和 GridView,指示他们的内容栈从底部开始 | |
android:transcriptMode | 设置该组件的滚动模式: disable:关闭滚动,这是默认值 normal:当该AbsListView收到数据改变通知,且最后一个列表项可见时,该AbsListView将会滚动到底端 alwayScroll:该AbsListView总会自动滚动到底端 |
ListView常用的XML属性
XML属性 | 说明 |
---|---|
android:divider | 设置List列表项的分隔条,即可用颜色分割也可用drawable分割 |
android:dividerHeight | 设置分隔条的高度 |
android:entries | 指定一个数组资源,用于生成列表项 |
android:footerDividersEnabled | 是否在footer View之前绘制分隔条 |
android:headerDividersEnabled | 与上面的类似,是否在header View之后绘制分隔条 |
Adapter及其实现类的继承关系图
常用的有:ArrayAdapter、SimpleAdapter、SimpleCursorAdapter、BaseAdapter。
作用:把复杂的数据(数组、链表、数据库、集合等)填充在指定视图界面上。
最常用的两种适配器:
ArrayAdapter(数组适配器),用于绑定单一的数据,数据源可以是集合或数组。
SimpleAdapter(简单适配器),用于绑定格式复杂的数据,数据源只能是特定泛型的集合。
数据适配器是连接数据源和视图界面的桥梁,起中介的作用。
实现过程:新建适配器->添加数据源到适配器->视图加载适配器
首先在布局文件中添加ListView控件
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/listView">
ListView>
使用一个数组适配器来连接数据源,然后视图绑定适配器
public class Test1Activity extends AppCompatActivity {
private ListView listView;
private ArrayAdapter arrAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test1);
listView = (ListView)findViewById(R.id.listView);
String []arrData = {"asde","请问","dasv","fads","sdaf"};
arrAdapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1,arrData);
listView.setAdapter(arrAdapter);
}
}
关于ArrayAdapter,创建ArrayAdapter需要三个参数。
context:上下文,代表了访问整个Android应用的接口,几乎创建所有组件都需要传入Context对象。
textViewResourceId:一个资源ID,该资源ID代表一个TextView,作为ListView中每行的样式,上面例子使用的安卓系统自带的样式,也可以使用自定义的样式,需要注意的是XML的根结点只能是TextView。
数组或List:该数组或List将负责为多个列表项提供数据。
下面使用SimpleAdapter实现图文并茂的ListView
SimpleAdapter比ArrayAdapter要复杂一些,但是功能更为强大。
首先还是在布局文件中添加ListView控件
activity_main.xml
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/lv1"
android:drawSelectorOnTop="true">
ListView>
然后创建一个图文的布局文件,用于ListView的每一个表项的布局
simpleadaitem.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="10dp"
android:adjustViewBounds="true"
android:maxWidth="100dp"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/author"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
LinearLayout>
LinearLayout>
关键的部分,创建一个SimpleAdapter,添加数据源,绑定到视图
package com.example.admin.test3;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Test2Activity extends AppCompatActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test2);
//获取布局中的ListView
final ListView lv1 = (ListView)findViewById(R.id.lv1);
//获取图片资源文件
int [] images = new int[]{R.drawable.img4,R.drawable.img5,R.drawable.img6,R.drawable.img7};
String []title = new String[]{"实战大数据——","白话深度学习与","Unity 3D\\2D手机游戏开发:从学习","Web前端自动化构"};
String []author = new String[]{"许国根,贾瑛","高扬","金玺曾","[澳]斯特凡·鲍姆加"};
//将上面的数据添加到List集合中
List
关于SimpleAdapter,使用SimpleAdapter的最大难点在于创建SimpleAdapter对象,它需要5个参数:
第一个参数:上下文,这个不用多说,写this即可。
第二个参数:该参数应该是一个List extends Map
类型的集合对象,该集合中每个Map
对象生成一个列表项。
第三个参数:该参数指定一个界面布局的ID,这里使用的自己创建的xml布局文件。
第四个参数:该参数是一个String[]类型的参数,该参数决定提取Map
对象中哪些key对应的value来生成列表项,所以填写map.put(key,Value)
对应的key即可。
第五个参数:该参数是一个int[]类型的参数,该参数决定填充哪些组件,填写自定义的xml布局文件中控件的ID即可,相当于把第四个参数指定的数据填充到第五个控件指定的控件中,与第四个参数形成对应关系。
OnItemClickListener:
可以处理视图中单个条目的点击事件
final TextView tv2 = (TextView)findViewById(R.id.tv2);
lv1.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView> adapterView, View view, int i, long l) {
TextView name = (TextView) view.findViewById(R.id.author);
tv2.setText(name.getText());
}
});
这段代码的作用是将点击到的条目中author内容显示到TextView中
onItemClick的参数:
adapterView是识别是哪个ListView发生的点击事件。
view是点击到的那一item的view的布局,就是可以用这个view,获取里面的控件的id后操作控件。
i是当前item在ListView中适配器里的位置。
l是当前item在ListView里的第几行的位置。
OnScrollListener:
ListView的滚动事件,监听滚动事件,可以做到下拉刷新,下拉显示更多列表的操作。
lv1.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView absListView, int i) {
switch(i){
case SCROLL_STATE_FLING:
Log.i("Main", "用户在手指离开屏幕之前,由于用力滑了一下,视图仍在滚动");
break;
case SCROLL_STATE_IDLE:
Log.i("Main", "视图已经停止滚动");
break;
case SCROLL_STATE_TOUCH_SCROLL:
Log.i("Main", "手指没有离开屏幕,视图正在滑动");
break;
}
}
@Override
public void onScroll(AbsListView absListView, int i, int i1, int i2) {
}
});
我们可以在onScrollStateChanged中进行判断,主要判断一下条件;
是否是停止状态
是否滑倒最后
是否正在加载数据
如果符合条件,则开始加载数据,通过接口回调,然后ListView加载更多数据。
Map map = new HashMap();
map.put("image",R.mipmap.ic_launcher);
map.put("text","我是拉到最下边没有之后刷新添加的");
dataList.add(map);
simple_adapter.notifyDataSetChanged();//适配器对象调用
notifyDataSetChange()方法,告诉UI界面更新告诉UI界面更新。
在屏幕下滑时,动态的加载入新的数据,也就是在Map中添加新的数据map.put(…),添加到SimpleAdapter初始化时用到的数据源dataList中dataList.add(map),同时适配器通知UI线程有数据更新。
BaseAdapter是一个抽象类,使得用户可以灵活的使用列表项,现在用BaseAdapter重新实现上例。
package com.example.admin.test3;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
public class Test3Activity extends AppCompatActivity {
private ListView myList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test3);
final int [] images = new int[]{R.drawable.img4,R.drawable.img5,R.drawable.img6,R.drawable.img7};
final String []title = new String[]{"实战大数据——","白话深度学习与","Unity 3D\\2D手机游戏开发:从学习","Web前端自动化构"};
final String []author = new String[]{"许国根,贾瑛","高扬","金玺曾","[澳]斯特凡·鲍姆加"};
myList = (ListView)findViewById(R.id.myList);
BaseAdapter adapter = new BaseAdapter() {
@Override
public int getCount() {
return 4;
}
@Override
public Object getItem(int i) {
return null;
}
@Override
public long getItemId(int i) {
return 0;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
LinearLayout line = new LinearLayout(Test3Activity.this);
line.setOrientation(LinearLayout.HORIZONTAL);
ImageView image = new ImageView(getApplicationContext());
image.setImageResource(images[i]);
image.setMaxWidth(200);
image.setAdjustViewBounds(true);
line.addView(image);
LinearLayout line2 = new LinearLayout(getApplicationContext());
line2.setOrientation(LinearLayout.VERTICAL);
TextView text = new TextView(Test3Activity.this);
text.setText(title[i]);
line2.addView(text);
TextView text2 = new TextView(Test3Activity.this);
text2.setText(author[i]);
line2.addView(text2);
line.addView(line2);
return line;
}
};
myList.setAdapter(adapter);
}
}
这部分代码的关键是在于重写了4个方法
getCount():该方法的返回值控制该Adapter将会包含多少个列表项。
getItem(int position):该方法的返回值决定第position处的列表项的内容。
getItemId(int position):该方法的返回值决定第position处的列表项的ID。
getView(int position,View convertView,ViewGroup parent):该方法的返回值决定第position处的列表项组件。
AdapterView的其它子类GridView、Spinner、Gallery和AdapterViewFlipper等用法与ListView相同。
自动完成文本框从EditText派生出来,当用户输入一定字符之后,自动完成文本框会显示一个下拉菜单,供用户从中选择,当用户选中某个菜单项之后,自动完成文本框会自动填写该文本框。
实现:
首先在布局文件中添加AutoCompleteTextView
<AutoCompleteTextView
android:id="@+id/auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:completionHint="请选择您喜欢的图书:"
android:completionThreshold="1"/>
然后写逻辑代码
package com.example.admin.test3;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
public class Test1Activity extends AppCompatActivity {
AutoCompleteTextView auto;
// 定义字符串数组,作为提示的文本
String[] books = new String[]{
"图书1",
"图书2",
"图书3",
"图书4"
};
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test1);
// 创建一个ArrayAdapter,封装数组
ArrayAdapter aa = new ArrayAdapter(this,
android.R.layout.simple_dropdown_item_1line, books);
auto = (AutoCompleteTextView)findViewById(R.id.auto);
// 设置Adapter
auto.setAdapter(aa);
}
}
运行截图:
还有一种MultiAutoCompleteTextView,它允许输入多个提示项,用法类似。
GridView用于在界面上按行、列分布的方式来显示多个组件。
GridView与ListView的区别在于ListView只显示一列,而GridView可以显示多列,它们的用法基本一致。
XML属性 | 相关方法 | 说明 |
---|---|---|
android:numColumns | setNumColumns(int) | 设置列数 |
android:horizontalSpacing | setHorizontalSpacing(int) | 设置个元素之间的水平间距 |
android:verticalSpacing | setVerticalSpacing(int) | 设置各元素之间的垂直间距 |
android:columnWidth | setColumnWidth(int) | 设置列的宽度 |
android:gravity | setGravity(int) | 设置对齐方式 |
android:stretchMode | setStretchMode(int) | 设置拉伸模式 |
注意:不能设置行高
ExpandableListView是ListView的之类,它在普通ListView的基础上进行了扩展,它把应用中的列表项分为几组,每组又可包含多个列表项。
Spinner其实就是一个列表选择框,效果是弹出一个菜单供用户选择。
示例:
<Spinner
android:id="@+id/spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content">
Spinner>
public class Test1Activity extends AppCompatActivity {
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test1);
String[] arr1 = new String[]{"驱蚊器","非常","分为","轻轻打发"};
ArrayAdapter adapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1,arr1);
Spinner spinner = (Spinner)findViewById(R.id.spinner);
spinner.setAdapter(adapter);
}
}
它们均继承于AdapterViewAnimator,共同特点是支持一定的动画特效,AdapterViewFlipper每次显示一个View组件,程序可通过showPrevious()和showNext()来显示上一个、下一个组件,还可以通过startFlipping()来控制它自动播放下一个View组件。StackView是以堆叠的方式来显示多个列表项。
示例:
使用AdapterViewFlipper实现自动播放的图片库
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<AdapterViewFlipper
android:id="@+id/flipper"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:flipInterval="5000"
android:layout_alignParentTop="true"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:onClick="prev"
android:text="上一个"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:onClick="next"
android:text="下一个"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:onClick="auto"
android:text="自动播放"/>
RelativeLayout>
package com.example.admin.test3;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterViewFlipper;
import android.widget.BaseAdapter;
import android.widget.ImageView;
public class Test4Activity extends AppCompatActivity {
int[] imageIds = new int[]{R.drawable.img4,R.drawable.img5,R.drawable.img6,R.drawable.img6,R.drawable.img7 };
private AdapterViewFlipper flipper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test4);
flipper = (AdapterViewFlipper) findViewById(R.id.flipper);
// 创建一个BaseAdapter对象,该对象负责提供Gallery所显示的列表项
BaseAdapter adapter = new BaseAdapter()
{
@Override
public int getCount()
{
return imageIds.length;
}
@Override
public Object getItem(int position)
{
return position;
}
@Override
public long getItemId(int position)
{
return position;
}
// 该方法返回的View代表了每个列表项
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
// 创建一个ImageView
ImageView imageView = new ImageView(getApplicationContext());
imageView.setImageResource(imageIds[position]);
// 设置ImageView的缩放类型
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
// 为imageView设置布局参数
imageView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
return imageView;
}
};
flipper.setAdapter(adapter);
}
public void prev(View source)
{
// 显示上一个组件
flipper.showPrevious();
// 停止自动播放
flipper.stopFlipping();
}
public void next(View source)
{
// 显示下一个组件。
flipper.showNext();
// 停止自动播放
flipper.stopFlipping();
}
public void auto(View source)
{
// 开始自动播放
flipper.startFlipping();
}
}
StackView示例:
<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:orientation="vertical"
tools:context="com.example.admin.test3.Test1Activity">
<StackView
android:id="@+id/stackView1"
android:layout_width="match_parent"
android:layout_height="400dp"
android:loopViews="true">
StackView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="上一个"
android:onClick="prev"/>
<Button
android:id="@+id/bututon1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下一个"
android:onClick="next"/>
LinearLayout>
LinearLayout>
public class Test1Activity extends AppCompatActivity {
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test1);
final int imageids[] = new int[]{R.drawable.img5,R.drawable.img6,R.drawable.img7,R.drawable.img4};
StackView stack = (StackView)findViewById(R.id.stackView1);
List> list = new ArrayList>();
for(int i=0;i map = new HashMap();
map.put("images",imageids[i]);
list.add(map);
}
SimpleAdapter adapter = new SimpleAdapter(this,list,R.layout.cell,
new String[]{"images"},new int[]{R.id.image1});
stack.setAdapter(adapter);
}
public void prev(View view){
StackView stack = (StackView)findViewById(R.id.stackView1);
stack.showPrevious();
}
public void next(View view){
StackView stack = (StackView)findViewById(R.id.stackView1);
stack.showNext();
}
}