Android开发-列表控件

列表控件是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中的列名列表。
tofrom参数的数据对应放置。都是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布局文件中扩展它。

参数
positionint:我们想要查看的项目的适配器数据集中项目的位置。
convertViewView:如果可能的话,要重用旧视图。注意:在使用之前,您应该检查此视图是否为非空且类型合适。如果无法将此视图转换为显示正确的数据,则此方法可以创建一个新视图。
parentViewGroup:此视图最终将附加到的父级

当视图被膨胀时,父视图(GridView, ListView…)将应用默认的布局参数,除非你使用

LayoutInflater.inflate(int, android.view.ViewGroup, boolean)来指定根视图并防止附加到根视图。

 public View inflate (int resource, 
                 ViewGroup root, 
                 boolean attachToRoot)

从指定的xml资源膨胀一个新的视图层次结构。

参数
resourceint: 要加载的 XML 布局资源的 ID(例如 )R.layout.main_page
rootViewGroup: 作为生成层次结构的父级的可选视图(如果 attachToRoot为 true),或者只是为返回的层次结构的根提供一组 LayoutParams 值的对象(如果attachToRoot为 false。)此值可能是null.
attachToRootboolean: 膨胀的层次结构是否应该附加到根参数?如果为 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)

制作一个只包含资源文本的标准祝酒词。

参数
contextContext: 当前的context,通常是你的应用程序或Activity
resIdint: 要使用的字符串资源的资源id。
durationint: 该消息显示多长时间。 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();
 }

总结:

自定义列表控件的大体使用方式:

  1. 获取数据(文件IO,网络,内存或数据库等)

  2. 整理数据成为相应的数据结构,一般为键值对的线性结构

  3. 数据结构是不能直接给列表控件的,需要建立适配器对象,并赋予数据结构

    1. 可以使用类库所提供的适配器对象,直接创建并使用

    2. 若希望自行设计列表样式,需要继承BaseAdapter,并重写相关函数

  4. 将适配器对象赋予列表控件,一般是调用setAdapet函数

  • 5
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值