列表控件是Android中最常见的控件之一
由于手机屏幕空间都比较有限,能够一次性在屏幕上显示的内容并不多,当我们的程序中有大量的数据需要展示的时候,就可以借助各种列表控件来实现。
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
显示可垂直滚动的视图集合,其中每个视图都位于列表中紧靠前一个视图的下方。
列表视图是一种适配器视图,它不知道它所包含的视图的详细信息,比如类型和内容。为了在列表中显示项目,调用setAdapter
将适配器与列表关联起来。
要为数据集中的每个项显示更自定义的视图,请实现一个ListAdapter。
列表控件一般包括ListView,GridView,以及目前用来代替前二者的RecycleView。
11.1、列表样式
样例:
1.前端写死
布局文件:
<ListView
android:id="@+id/listview1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="#C4C4C4"
android:entries="@array/teacher_name"
android:dividerHeight="1dp">
</ListView>
-
divider:行分割线颜色
-
dividerHeight:分割线宽度
-
entries:数据入口参数(使用资源文件引用)
资源文件编写:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--添加数组元素-->
<string-array name="teacher_name">
<item>董二</item>
<item>张三</item>
<item>李四</item>
<item>王五</item>
<item>赵六</item>
</string-array>
</resources>
通过定义一个字符串数组来存放字符串数据
2.后端获取显示
布局文件:
<ListView
android:id="@+id/listview1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="#C4C4C4"
android:dividerHeight="1dp">
</ListView>
去掉数据源,样式保留
后端数据获取:
在这里直接给出数据,此处数据可由网络获取,也可由数据库获取
ArrayAdapter
protected void onCreate(Bundle savedInstanceState) {
//dongyh Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.arradp2);
String str[] = {"Tom","Jerry","Mike","John","dongyh"};
//创建ArrayAdapter对象
ArrayAdapter<Object> aa
= new ArrayAdapter<Object>(
this, android.R.layout.simple_list_item_1, str
);
ListView lv = (ListView)this.findViewById(R.id.listview1);
//通过setAdapter函数实现赋值
lv.setAdapter(aa);
}
源码构造方法
public ArrayAdapter (Context context,
int resource,
T[] objects)
/*
para1:context:组件引用,即当前activity页面
para2:resource:列表控件的布局样式,这里使用了Android类库中定义的样式
注:这一类样式本身是Android系统自用的,不提倡在App中引用
para3:objects:数据资源集
您可以使用此适配器为AdapterView提供视图,为您提供的数据对象集合中的每个对象返回视图,并可与基于列表的用户界面小部件(如ListView或Spinner)一起使用。
*/
ArrayAdapter绑定的数据是集合或数组,比较单一
SimpleAdapter
//姓名
private String[] name={"张三","李四","王五"};
//爱好
private String[] desc={"跳舞","打球","跑步"};
//图标数组
private int[] icon=new int[]
{R.drawable.icon1,R.drawable.icon2,R.drawable.icon3};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ly_exp2);
//通过list对象来存储每一行的信息,list中用map对象通过键值对来对应存放信息
List<Map<String,Object>> list= new ArrayList<Map<String,Object>>();
for(int i=0;i<name.length;i++){
Map<String, Object> listitem=new HashMap<String, Object>();//key:string,value:object
listitem.put("icon",icon[i]);
listitem.put("name",name[i]);
listitem.put("desc",desc[i]);
list.add(listitem);
}
//设置listview内容要为其定义一个适配器
//这里使用SimpleAdapter适配器来进行数据赋值
//一个简单的适配器,可以将静态数据映射到XML文件中定义的视图。
SimpleAdapter sa = new SimpleAdapter(this,
list,
R.layout.ly_mylv,
new String[]{"desc","icon","name"},
new int[]{R.id.dexc,R.id.icon,R.id.name});
//通过设置适配器给listview赋值
((ListView)findViewById(R.id.mylv)).setAdapter(sa);
}
源码构造方法:
public SimpleAdapter (Context context,
List<? extends Map<String, ?>> data,
int resource,
String[] from,
int[] to)
参数 | 含义 |
---|---|
context | 与此SimpleAdapter 关联的视图正在运行的上下文 |
data | 地图列表。List中的每个条目对应于列表中的一行。map 包含每一行的数据,并且应该包括from 中指定的所有条目 |
resource | 视图布局的资源标识符,它定义了这个列表项的视图。布局文件至少应该包括那些在to 中定义的命名视图 |
from | 将添加到与每个项目关联的Map中的列名列表。 |
to | 与from 参数的数据对应放置。都是TextView 类型。这个列表中的前N个视图被赋予from 参数中的前N个列的值。 |
自定义Adapter
要为数据集中的每个项显示自定义的视图,请实现一个ListAdapter。
BaseAdapter:Adapter的公共实现的公共基类,它可以在ListView(通过实现专用的ListAdapter接口)和Spinner(通过实现专用的SpinnerAdapter接口)中使用。
private class MyAdapter extends BaseAdapter {
// override other abstract methods here
@Override
public View getView(int position, View convertView, ViewGroup container) {
if (convertView == null) {
convertView = getLayoutInflater().inflate(R.layout.list_item, container, false);
}
//对象赋值
((TextView) convertView.findViewById(android.R.id.text1))
.setText(getItem(position));
return convertView;
}
}
其中的getview方法是Adapter类下的
public abstract View getView (int position,
View convertView,
ViewGroup parent)
获取一个视图,显示数据集中指定位置的数据。你可以手动创建一个视图,也可以从XML布局文件中扩展它。
参数 | |
---|---|
position | int :我们想要查看的项目的适配器数据集中项目的位置。 |
convertView | View :如果可能的话,要重用旧视图。注意:在使用之前,您应该检查此视图是否为非空且类型合适。如果无法将此视图转换为显示正确的数据,则此方法可以创建一个新视图。 |
parent | ViewGroup :此视图最终将附加到的父级 |
当视图被膨胀时,父视图(GridView, ListView…)将应用默认的布局参数,除非你使用
LayoutInflater.inflate(int, android.view.ViewGroup, boolean)
来指定根视图并防止附加到根视图。
public View inflate (int resource,
ViewGroup root,
boolean attachToRoot)
从指定的xml资源膨胀一个新的视图层次结构。
参数 | |
---|---|
resource | int : 要加载的 XML 布局资源的 ID(例如 )R.layout.main_page |
root | ViewGroup : 作为生成层次结构的父级的可选视图(如果 attachToRoot为 true),或者只是为返回的层次结构的根提供一组 LayoutParams 值的对象(如果attachToRoot为 false。)此值可能是null . |
attachToRoot | boolean : 膨胀的层次结构是否应该附加到根参数?如果为 false,则 root 仅用于为 XML 中的根视图创建正确的 LayoutParams 子类。 |
当我们的自定义的适配器在绘制当前指定的item时会自动调用getview函数
public class excer3_basep1 extends BaseAdapter {
Context context;
List<Map<String,Object>> list;
public excer3_basep1(Context context, List<Map<String,Object>> list) {
super();
this.context=context;
this.list=list;
}
//设置列表控件对应不同数据需要重复绘制的次数,即item的个数
@Override
public int getCount() {
return list.size();
}
//针对每个item的操作
@Override
public Object getItem(int i) {
return null;
}
@Override
public long getItemId(int i) {
return 0;
}
//负责为每个item对应的数据加以绘制
@Override
public View getView(int position, View convertView, ViewGroup container) {
if (convertView == null) {
//convertView 系统传入的一个View对象,该对象作为某一个item的显示(绘制)的对象
convertView = LayoutInflater.from(context).inflate(R.layout.exp3_lvly1, container, false);
//.from:标记所要填充的组件
//inflate是安卓将xml实例化(转换代码)的工具。
}
//通过convertView视图转换器获取布局对象
ImageView icon=((ImageView) convertView.findViewById(R.id.exp3_lvly1_icon));
TextView name=(TextView) convertView.findViewById(R.id.exp3_lvly1_name);
TextView hobby=(TextView) convertView.findViewById(R.id.exp3_lvly1_hobby);
//赋值
icon.setImageResource((Integer) list.get(position).get("icon"));
name.setText(list.get(position).get("name").toString());
hobby.setText(list.get(position).get("hobby").toString());
return convertView;
}
}
代码优化:
convertView
Adapter的getView()方法中每次都将布局重新加载了一遍,当ListView快速滚动时,就会称为性能的瓶颈
getView()中还有一个convertView参数,这个参数用于将之前加载好的布局进行缓存,以便以后可以重用
findViewById
findViewById()
函数会在每次调用时,去R文件中搜索相匹配的id号,导致运行效率的降低
新增一个静态内部类ViewHolder
,用于对ListView
布局中控件的实例进行缓存
当convertView
为空时,将控件的实例引用都存放在ViewHolder
对象里
调用View类中的setTag()
函数,将ViewHolder
对象与convertView
关联起来
public void setTag (Object tag)
//设置与此视图相关联的标记。标记可以用于在层次结构中标记视图,并且在层次结构中不必是唯一的。标记还可以用于在视图中存储数据,而无需求助于其他数据结构。
当convertView
已经存在后,每次调用getTag()
获取ViewHolder
对象,并从中获取控件的引用
这样就无需每次都调用findViewById()
函数,提高运行效率
public class ViewHolder{
ImageView iv;
TextView tv1,tv2;
}
@Override
public View getView(int position, View convertView, ViewGroup container) {
ViewHolder vh=new ViewHolder();
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.exp3_lvly1, container, false);
vh.iv=((ImageView) convertView.findViewById(R.id.exp3_lvly1_icon));
vh.tv1=(TextView) convertView.findViewById(R.id.exp3_lvly1_name);
vh.tv2=(TextView) convertView.findViewById(R.id.exp3_lvly1_hobby);
convertView.setTag(vh);
}else {
vh=(ViewHolder) convertView.getTag();
}
//赋值
vh.iv.setImageResource((Integer) list.get(position).get("icon"));
vh.tv1.setText(list.get(position).get("name").toString());
vh.tv2.setText(list.get(position).get("hobby").toString());
return convertView;
}
11.2、Toast
public static Toast makeText (Context context,
int resId,
int duration)
制作一个只包含资源文本的标准祝酒词。
参数 | |
---|---|
context | Context : 当前的context,通常是你的应用程序或Activity |
resId | int : 要使用的字符串资源的资源id。 |
duration | int : 该消息显示多长时间。 LENGTH_SHORT or LENGTH_LONG |
为每一个列表行设置其显示的文本
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
msg="position:"+(i+1)+" name:"+name[i]+" hobby:"+hobby[i];
onshow();
}
});
}
void onshow(){
if(msg!=null)
Toast.makeText(this,msg,Toast.LENGTH_SHORT).show();
}
总结:
自定义列表控件的大体使用方式:
-
获取数据(文件IO,网络,内存或数据库等)
-
整理数据成为相应的数据结构,一般为键值对的线性结构
-
数据结构是不能直接给列表控件的,需要建立适配器对象,并赋予数据结构
-
可以使用类库所提供的适配器对象,直接创建并使用
-
若希望自行设计列表样式,需要继承
BaseAdapter
,并重写相关函数
-
-
将适配器对象赋予列表控件,一般是调用
setAdapet
函数