ListView使用详解

OPhone开发中经常会用到各种各样的组件,像TextView,Button等等。其中经常会使用到ListView(列表),ListView以列表的形式展示具体内容,并且能够根据数据的长度自适应显示。本篇将由浅入深的介绍几种列表,并着重介绍如何自定义列表。具体的表现形式如图1所示。在OPhone系统中,列表的显示需要三个元素:

 
1.ListVeiw 用来展示列表的View。
2.适配器 用来把数据映射到ListView上的中介。
3.数据    具体的将被映射的字符串,图片,或者基本组件。
 
根据列表的适配器类型,列表分为三种,ArrayAdapter,SimpleAdapter和SimpleCursorAdapter
其中以ArrayAdapter最为简单,只能展示一行字,如图1所示。SimpleAdapter有最好的扩充性,可以自定义出各种效果。SimpleCursorAdapter可以认为是SimpleAdapter对数据库的简单结合,可以方面的把数据库的内容以列表的形式展示出来。
 
ArrayAdapter
使用ArrayAdapter显示列表非常简单。代码如下:
 
  1. public class List1 extendsActivity {   
  2.     
  3.     private ListVeiw listView;   
  4.     @Override  
  5.     public void onCreate(Bundle savedInstanceState) {   
  6.    super.onCreate(savedInstanceState);   
  7.     
  8.        listView=new ListVeiw(this);   
  9.        listView.setAdapter(new ArrayAdapter<String>(this,   
  10.            android.R.layout.simple_list_item_1, mStrings));   
  11.       setContentVieww(listView);   
  12.         }   
  13.     
  14.    private String[] mStrings = {   
  15.            "Abbaye de Belloc""Abbaye du Mont des Cats",       
  16.            "Acorn""Adelost""Affidelice au Chablis",    
  17.            "Aisy Cendre""Allgauer Emmentaler""Alverca",    
  18.            "Ami du Chambertin""Anejo Enchilado", "Anneau    
  19.            "Aragon""Ardi Gasna""Ardrahan", "Armenian    
  20.            "Asadero""Asiago""Aubisque Pyrenees""Autun",    
  21.             "Babybel""Baguette Laonnaise""Bakers""Bal"};   
  22. }  
 
 
上面代码首先定义一个ListView类型的View对象,用来显示视图。其次使用ArrayAdapter(数组适配器)顾名思义,需要把数据放入一个数组以便显示。ListView如何显示数组中的数据呢?这就需要一个连接ListView视图对象和数组数据的适配器来两者的适配工作。数组适配器的构造需要三个参数,依次为this,布局文件(注意这里的布局文件描述的是列表的每一行的布局,android.R.layout.simple_list_item_1是系统定义好的布局文件只显示一行文字,有许多这样的文件,可以在OPhone目录的OPhoneSDK_1.5\platforms\android-1.5\data\res\layout下面查看),数组。同时用setAdapter()完成适配的最后工作。此段代码的显示效果如图1所示。
 
 
 
             图1 数组适配器显示的列表
 
SimpleCursorAdapter
 
SimpleCursorAdapter使用起来也是非常简单。下面以读取通讯录数据库为例加以介绍。首先为了保证列表的显示,你应该至少在通讯录中添加一个联系人作为数据库的数据。然后获得一个指向数据库的Cursor并且定义一个布局文件(当然也可以使用系统自带的)。
代码如下:
 
 
  1. public class List2 extends Activity {   
  2.        
  3.     private ListView listView;   
  4.     @Override  
  5.     protected void onCreate(Bundle savedInstanceState) {   
  6.         super.onCreate(savedInstanceState);   
  7.     
  8.         listView=new ListView(this);   
  9.        Cursorc=getContentResolver().query(People.CONTENT_URI,   
  10.        nullnullnullnull);         
  11.         startManagingCursor(c);   
  12.     
  13.         ListAdapter adapter = new SimpleCursorAdapter(this,    
  14.                  android.R.layout.simple_list_item_1,   
  15.                  c,    
  16.                  new String[] {People.NAME} ,   
  17.                  new int[] {android.R.id.text1});    
  18.         listView.setAdapter(adapter);   
  19. setContentView(listView);   
  20. }   
  21. }  
 
 
在上面的ArrayAdapter里面也许读者并没有理解映射的概念,因为是系统自己做了映射。这段程序将告诉你什么是映射。首先定义用来显示的ListView对象,然后获得一个指向系统通讯录数据库的Cursor对象获得数据来源。我们将获得的Cursor对象交由Activity管理,这样Cursor的生命周期和Activity便能够自动同步,省去自己手动管理Cursor。或者使用managerQuery()方法代替query。)也可以得到同样的效果。下面要做的是将数据库数据映射到ListView实例上。需要定义SimpleCursorAdapter,他的五个参数依次为this,布局文件,Cursor实例,一个包含数据库的列的String型数组,一个包含布局文件中对应组件id的int型数组。SimpleCursorAdapter做的工作就是自动的将String型数组所表示的每一列数据映射到布局文件对应id的组件上。上面的代码,将NAME列的数据一次映射到布局文件的id为text1的组件上。
 
效果如图2 所示:
 
 
 
       图2 使用SimpleCursorAdapter显示的列表
 
上面的Ntopo,Liuzhoyun,Kun,Android,Nexus One是我添加的联系人名字。
 
SimpleAdapter
 
有图片的ListView
 
SimpleAdapter放在最后,因为它太有意思了。你能定义各种各样的布局出来,可以放上ImageView(图片),还可以放上Button(按钮),CheckBox(复选框)等等。在此有必要说一下ListActivity。ListActivity和普通的Activity没有太大的差别,不同就是对显示ListView做了许多优化,方面显示而已。
 
下面的例子将显示一张图片和两行文字,效果如下图3示:
 
 
 
       图 3 有图片的ListView
 
 
首先定义一个布局文件,item.xml内容如下:
  1. <?xml version="1.0" encoding="utf-8"?>   
  2. <LinearLayout   
  3.  xmlns:android="http://schemas.android.com/apk/res/android"  
  4.  android:layout_width="wrap_content"  
  5.  android:layout_height="wrap_content"  
  6.  android:orientation="horizontal">   
  7.     
  8.  <ImageView android:id="@+id/img"  
  9.  android:layout_width="wrap_content"  
  10.  android:layout_height="wrap_content"  
  11.  />   
  12.  <LinearLayout android:orientation="vertical"  
  13.  android:layout_width="wrap_content"  
  14.  android:layout_height="wrap_content"  
  15.  >   
  16.  <TextView android:id="@+id/BigText"  
  17.  android:layout_width="wrap_content"  
  18.  android:layout_height="wrap_content"  
  19.  android:textColor="#FFFFFFFF"  
  20.  android:textSize="30px"  
  21.  />   
  22.  <TextView android:id="@+id/LittleText"  
  23.  android:layout_width="wrap_content"  
  24.  android:layout_height="wrap_content"  
  25.  android:textColor="#FFFFFFFF"  
  26.  android:textSize="15px"  
  27.  />   
  28.  </LinearLayout>   
  29.     
  30.     
  31. </LinearLayout>  
 
 
然后JavaCode如下:
  1. public class List3 extends ListActivity {   
  2.        
  3.     List<Map<String, Object>> list;   
  4.     
  5.     @Override  
  6.     public void onCreate(Bundle savedInstanceState) {   
  7.        super.onCreate(savedInstanceState);   
  8.           
  9.        list = getListForSimpleAdapter();   
  10.     
  11.        SimpleAdapter     adapter = new SimpleAdapter(this, list,   
  12. R.layout.item,   
  13.        new String[] { "BigText""LittleText""img" },    
  14. new int[] { R.id.BigText,R.id.LittleText, R.id.img });   
  15.     
  16.        setListAdapter(adapter);   
  17.        
  18.     
  19.     }   
  20.     
  21.     private List<Map<String, Object>> getListForSimpleAdapter() {   
  22.     List<Map<String,Object>> list=newArrayList<Map<String,        Object>>(3);   
  23.            Map<String, Object> map = new HashMap<String, Object>();   
  24.            map.put("BigText""Android");   
  25.            map.put("LittleText""Google phone.");   
  26.            map.put("img", R.drawable.n);   
  27.            list.add(map);   
  28.     
  29.            map = new HashMap<String, Object>();   
  30.            map.put("BigText""Lenovo");   
  31.            map.put("LittleText""Ophone");   
  32.            map.put("img", R.drawable.o);   
  33.            list.add(map);   
  34.     
  35.            map = new HashMap<String, Object>();   
  36.            map.put("BigText""Droid");   
  37.            map.put("LittleText""Motorola");   
  38.            map.put("img", R.drawable.droid);   
  39.            list.add(map);   
  40.     
  41.           
  42.        return list;   
  43.     }   
  44.     
  45.     
  46. }   
  47.    
 
 
用SimpleAdapter做适配,数据来源不是一个数据库的Cursor实例,不是数组,往往是用一个有HashMap构成的List,我们在list中插入HashMap类型数据,作为数据来源。list的每一节对应ListView的每一行。HashMap的每个键值数据映射到布局文件中对应id的组件上。有图片的ListView首先准备些图片和数据,这个工作在getListForSimpleAdapter()中完成了。因为系统没有对应的布局文件可用,我们可以自己定义一个布局item.xml。下面做适配,new一个SimpleAdapter参数一次是:this,布局文件(item.xml),HashMap的BigText和LittleText,img。布局文件的组件id,BigText,LittleText,img。布局文件的各组件分别映射到HashMap的各元素上,完成适配。
 
 
有按钮的ListView
 
但是有时候,列表不光会用来做显示用,我们同样可以在在上面添加按钮。添加按钮首先要写一个有按钮的xml文件,然后自然会想到用上面的方法定义一个适配器,然后将数据映射到布局文件上。但是事实并非这样,因为按钮是无法映射的,即使你成功的用布局文件显示出了按钮也无法添加按钮的响应,这时就要研究一下ListView是如何现实的了,而且必须要重写一个类继承BaseAdapter。下面的示例将显示一个按钮和一个图片,两行字如果单击按钮将删除此按钮的所在行。并告诉你ListView究竟是如何工作的。效果如下:
 
 
              图 4   有按钮的ListView
 
布局文件是在上面的item.xml里添加一个按钮:
 
 
  1. <Button android:id="@+id/bt"  
  2.  android:layout_height="wrap_content"  
  3.  android:layout_width="wrap_content"  
  4.  android:text="Details"  
  5.  android:layout_gravity="bottom|right"  
  6.  />  
 
JavaCode如下:
 
  1. public class List3 extends ListActivity {   
  2.        
  3.     private String []phone={"Android","Lenovo","Droid"};   
  4.     private String []maker={"Google phone","Ophone","Motorola"};   
  5.     private    int[]imgid={R.drawable.n,R.drawable.o,R.drawable.droid};   
  6.     
  7.     @Override  
  8.     public void onCreate(Bundle savedInstanceState) {   
  9.        super.onCreate(savedInstanceState);   
  10.     
  11.        MyAdapter adapter = new MyAdapter(this);   
  12.        setListAdapter(adapter);   
  13.     
  14.     }   
  15.     
  16.     public void sdelete(){   
  17.                  
  18.         new AlertDialog.Builder(this)   
  19.         .setTitle("自定义ListVeiw")   
  20.         .setMessage("oh,you clicked the button")   
  21.         .setPositiveButton("确定",   
  22.          new DialogInterface.OnClickListener()   
  23.         {   
  24.           publicvoid onClick(DialogInterface dialog, intwhButton)   
  25. {   
  26. }   
  27. })   
  28.         .show();   
  29.     }   
  30.        
  31.     public final class ViewHolder{   
  32.         public TextView BigText;   
  33.         public TextView LittleText;   
  34.         public ImageView img;   
  35.         public Button sdelete;   
  36.     }   
  37.        
  38.     public class MyAdapter extends BaseAdapter   
  39.     {   
  40.         private LayoutInflater inflater;   
  41.         private Context mcontext=null;//assume 2 data   
  42.            
  43.         public MyAdapter(Context context){   
  44.               
  45.                this.mcontext=context;   
  46.                inflater=LayoutInflater.from(mcontext);   
  47.                   
  48.        }   
  49.        public int getCount() {   
  50.            return phone.length;   
  51.        }   
  52.     
  53.        public Object getItem(int arg0) {   
  54.            return null;   
  55.        }   
  56.     
  57.        public long getItemId(int arg0) {   
  58.            return 0;   
  59.        }   
  60.     
  61.        public View getView(int position, View convertView,   
  62.        ViewGroup parent) {   
  63.     
  64.            ViewHolder holder;   
  65.            if(convertView==null){   
  66.                  
  67.               convertView =inflater.inflate(R.layout.item,null);   
  68.               holder=new ViewHolder();   
  69.               holder.BigText=(TextView)convertView.findViewById(R.id.BigText   
  70. );   
  71. holder.LittleText=(TextView)convertView.findViewById(R.id.LittleText);   
  72.     holder.img=(ImageView)convertView.findViewById(R.id.img);   
  73.     holder.sdelete=(Button)convertView.findViewById(R.id.bt);   
  74.                  
  75.                  
  76.               holder.BigText.setText(phone[position]);   
  77.               holder.LittleText.setText(maker[position]);   
  78.               holder.img.setBackgroundResource(imgid[position]);   
  79.                  
  80.               convertView.setTag(holder);   
  81.                  
  82. holder.sdelete.setOnClickListener(new Button.OnCli ckListener(){   
  83.               public void onClick(View arg0) {   
  84.                      // TODO Auto-generated method stub   
  85.                      sdelete();   
  86.                   }   
  87.            });   
  88.                  
  89.                  
  90.            }else{   
  91.                  
  92.               holder=(ViewHolder)convertView.getTag();   
  93.                  
  94.               holder.BigText.setText(phone[position]);   
  95.               holder.LittleText.setText(maker[position]);   
  96.               holder.img.setBackgroundResource(imgid[position]);   
  97.                   
  98.               holder.sdelete.setOnClickListener(new    
  99.                 Button.OnClickListener(){   
  100.               public void onClick(View v) {   
  101.                      // TODO Auto-generated method stub   
  102.                 sdelete();   
  103.                   }   
  104.                      
  105.               });   
  106.            }   
  107.               
  108.            return convertView;   
  109.     
  110.        }   
  111.      }   
  112.  }  
 
下面将对上述代码,做详细的解释,listView在开始绘制的时候,系统首先调用getCount()函数,根据他的返回值得到listView的长度(这也是为什么在开始的第一张图特别的标出列表长度),然后根据这个长度,调用getView()逐一绘制每一行。如果你的getCount()返回值是0的话,列表将不显示同样return 1,就只显示一行。
 
 
             图 5 返回不同长度显示列表也不同
 
 
 
系统显示列表时,首先实例化一个适配器(这里将实例化自定义的适配器)。当手动完成适配时,必须手动映射数据,这需要重写getView()方法。系统在绘制列表的每一行的时候将调用此方法。getView()有三个参数,position表示将显示的是第几行,covertView是从布局文件中inflate来的布局。我们用LayoutInflater的方法将定义好的item.xml文件提取成View实例用来显示。然后将xml文件中的各个组件实例化(简单的findViewById()方法)。这样便可以将数据对应到各个组件上了。但是按钮为了响应点击事件,需要为它添加点击监听器,这样就能捕获点击事件。至此一个自定义的listView就完成了,现在让我们回过头从新审视这个过程。系统要绘制ListView了,他首先获得要绘制的这个列表的长度,然后开始绘制第一行,怎么绘制呢?调用getView()函数。在这个函数里面首先获得一个View(实际上是一个ViewGroup),然后再实例并设置各个组件,显示之。好了,绘制完这一行了。那再绘制下一行,直到绘完为止。在实际的运行过程中会发现listView的每一行没有焦点了,这是因为Button抢夺了listView的焦点,只要布局文件中将Button设置为没有焦点就OK了。
原文地址:https://www.cnblogs.com/tt_mc/p/1697079.html