列表控件是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 函数
|