ListView的使用技巧

一 原理分析

ListView是Android中非常重要的控件之一,Android对ListView做了特殊的设计与优化,尤其是在显示大量数据时,使用ListView的小技巧,可以得到更好的用户体验,下面就来介绍这些常用的技巧。


1)复用convertView

ListView在需要显示Item的时候,会首先检查回收站里是否有缓存的item,如果发现有缓存的item,ListView会直接复用它,把它作为参数传递给Adapter的getView方法,参数名为convertView。
所以如果convertView不为空,表明回收站中存在可以复用的Item,就不需要在创建新的Item了。
这种View复用的方式适用于单一Item视图和多种Item视图的情况,在之前的例子中已经提到过,可以参考以前的讲解。
View复用的示例代码如下:

1 public View getView(int position, View convertView, ViewGroup parent) {
2             if (convertView == null) {
3                 convertView = getLayoutInflater().inflate(R.layout.text_item, parent,false);
4             }
5             return convertView;
6         }


2)使用ViewHolder

在Android中,在操作一个控件的时,首先需要通过findViewById从控件树中找到它,然后才能对它进行操作。而对于ListView中的Item布局文件的解析式重复性的,因此每次都执行findViewById方法非常耗时。
常用的做法是定义一个ViewHolder类来缓存查找后的控件引用,这样只需要在初始化的时候查找一次,以后对控件的操作都可以直接从ViewHolder中获取。

01 @Override
02 public View getView(int position, View convertView, ViewGroup parent) {
03 // TODO Auto-generated method stub
04  
05 ViewHolder vh = null;
06  
07 if(convertView == null) {
08  
09 vh = new ViewHolder();
10  
11 if(getItemViewType(position) == FIRST_LETTER_ITEM) {
12 convertView = getLayoutInflater().inflate(R.layout.first_letter_item, parent, false);
13 //convertView = mInflater.inflate(R.layout.first_letter_item, null);
14 vh.tv = (TextView) convertView.findViewById(R.id.firstletter);
15  
16 else {
17 convertView = getLayoutInflater().inflate(R.layout.word_item, parent, false);
18 //convertView = mInflater.inflate(R.layout.word_item, null);
19 vh.tv = (TextView) convertView.findViewById(R.id.word);
20 }
21 convertView.setTag(vh);
22 else {
23 vh = (ViewHolder) convertView.getTag();
24 }
25 vh.tv.setText(letter[position]);
26 return convertView;
27 }
28 class ViewHolder{
29 TextView tv;
30 }
             

其中,通过setTag和getTag的方式来存储和获取ViewHolder。省去了每次执行findViewById的时间。

3)刷新ListView的数据

Adapter处于ListView和数据的中间,当有数据变化时需要Adapter通知ListView刷新显示的内容。Adapter 提供了notifyDataSetChanged()和notifyDataSetInvalidated()两个方法通知ListView刷新。当有数据更新时调用notifyDataSetChanged方法,当数据完全无效时调用notifyDataSetInvalidated方法。

4)Header和Footer

ListView除了显示Item以为,还可以显示Header和Footer。ListView提供了addHeaderView和addFooterView方法添加Header和Footer。需要注意的是:必须在给ListView设置Adapter之前,调用这两个方法添加header或者footer,否则会抛出异常。

5)使用selector美化listView

通过设置ListView的listSelector属性,可以为listView的Item设置选中,点击等显示效果。在Android中可以使用listView的setSelector方法或者在xml文件中设置android:listSelector属性来设置ListView的selector属性。还可以设置ListView的android:drawSelectorOnTop属性,把selector绘制在item背景之后。

6)在ListView的Item之间显示分割线

通过ListView的android:divider属性或者setDivider方法可以修改Item之间的分割线。也可以给android:divider属性设置图片、颜色,或者设置为@drawable/@null(表示无分割线)。在使用android:divider属性时,同时还可以使用dividerHeight属性设置分割线占据的高度。

7)使用transcriptMode和stackFromBottom属性

ListView有两个比较特殊的属性android:transcriptMode和android: stackFromBottom。使用transcriptMode属性可以在有数据变化的时候让listView自动滚动到底部。transcriptMode可设置为一下三个不同的值:
disabled:禁用transcriptMode属性;
normal:如果最后一个item可见,滚动到底部;
alwaysScroll:总是自动滚动到底部;

使用stackFromBottom属性可以设置item从底部向上开始排列。通常在聊天、短信类型的应用中使用stackFromBottom和transcriptMode属性可以得到很好的显示效果。

效果如下图所示:

QQ截图20120514191351.png

图1   短信应用中ListView的显示效果


8) ListView的其他属性


以下几个属性和方法在ListView的使用中也比较重要,列举如下:
android:fastScrollEnabled;
android:smoothScrollbar;
android:cacheColorHint;
android:fadingEdge="vertical|horizontal|none";
setTextFilterEnabled()方法;


在此不做过多介绍,读者可以自行查资料,并进行验证。


二 示例分析


下面通过两个demo,将以上所讲到的ListView的特性分别进行演示和验证。


1) Demo1
JAVA1代码如下:


01 package com.devdiv.test.listviewtest7;
02  
03 import android.app.Activity;
04 import android.os.Bundle;
05 import android.view.View;
06 import android.widget.ArrayAdapter;
07 import android.widget.Button;
08 import android.widget.ListView;
09  
10 public class ListViewTest7Activity extends Activity {
11  
12 ListView mListView;
13 ArrayAdapter<String> mAdapter;
14  
15 public static final String CHEESES[] = {
16 "Abbaye de Belloc""Abbaye du Mont des Cats""Abertam""Abondance""Ackawi","Acorn""Adelost""Affidelice au Chablis",
17 "Afuega'l Pitu""Airag""Airedale""Aisy Cendre""Allgauer Emmentaler""Alverca","Ambert""American Cheese",
18 "Abbaye de Belloc""Abbaye du Mont des Cats""Abertam""Abondance""Ackawi","Acorn""Adelost""Affidelice au Chablis",
19 "Afuega'l Pitu""Airag""Airedale""Aisy Cendre""Allgauer Emmentaler""Alverca","Ambert""American Cheese",
20 "Abbaye de Belloc""Abbaye du Mont des Cats""Abertam""Abondance""Ackawi","Acorn""Adelost""Affidelice au Chablis",
21 "Afuega'l Pitu""Airag""Airedale""Aisy Cendre""Allgauer Emmentaler""Alverca","Ambert""American Cheese",
22 "Abbaye de Belloc""Abbaye du Mont des Cats""Abertam""Abondance""Ackawi","Acorn""Adelost""Affidelice au Chablis",
23 "Afuega'l Pitu""Airag""Airedale""Aisy Cendre""Allgauer Emmentaler""Alverca","Ambert""American Cheese",
24 };
25  
26 /** Called when the activity is first created. */
27 @Override
28 public void onCreate(Bundle savedInstanceState) {
29 super.onCreate(savedInstanceState);
30 setContentView(R.layout.main);
31  
32 //mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, CHEESES);
33 mAdapter = new ArrayAdapter<String>(this, R.layout.my_list_item, CHEESES);
34  
35 mListView = (ListView) findViewById(R.id.list);
36  
37 //mListView.setFastScrollEnabled(true);
38  
39 Button mButton = new Button(this);
40 mButton.setText("this is the header");
41 mListView.addHeaderView(mButton);
42  
43 Button mButton2 = new Button(this);
44 mButton2.setText("this is the footer");
45 mListView.addFooterView(mButton2);
46  
47 mListView.setAdapter(mAdapter);
48  
49 mListView.setTextFilterEnabled(true);
50  
51 }
52  
53 public void onDrawSelectorOnTop(View v) {
54 mListView.setSelector(R.drawable.selector_on_top);
55 mListView.setDrawSelectorOnTop(true);
56  
57 }
58  
59 public void onUseSelectorAsBackground(View V) {
60 mListView.setSelector(R.drawable.selector_as_background);
61 mListView.setDrawSelectorOnTop(false);
62  
63 }
64 }


所引用的布局文件main.xml的内容如下:


01 <?xml version="1.0" encoding="utf-8"?>
02 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
03 android:layout_width="fill_parent"
04 android:layout_height="fill_parent"
05 android:orientation="vertical" >
06  
07 <ListView
08 android:id="@+id/list"
09 android:layout_width="fill_parent"
10 android:layout_height="0dp"
11 android:layout_weight="1"
12  
13 android:fastScrollEnabled="true"
14  
15 android:fadingEdge="horizontal"
16 android:fadingEdgeLength="10dp"
17  
18 android:divider="#efefef"
19 android:dividerHeight="2dp"
20  
21 />
22  
23 <LinearLayout
24 style="@android:style/ButtonBar"
25 android:layout_width="fill_parent"
26 android:layout_height="wrap_content"
27 android:orientation="horizontal">
28  
29 <Button
30 android:layout_width="0dp"
31 android:layout_height="fill_parent"
32 android:layout_weight="1"
33 android:layout_gravity="center_vertical"
34 android:text="@string/draw_selector_on_top"
35 android:onClick="onDrawSelectorOnTop"
36 />
37  
38 <Button
39 android:layout_width="0dp"
40 android:layout_height="fill_parent"
41 android:layout_weight="1"
42 android:layout_gravity="center_vertical"
43 android:text="@string/use_selector_as_background"
44 android:onClick="onUseSelectorAsBackground" />
45  
46 </LinearLayout>
47  
48 </LinearLayout>


下面,对JAVA代码和布局文件进行分析。


JAVA代码中,为ListView设置header和footer的代码部分如下:

1 Button mButton = new Button(this);
2 mButton.setText("this is the header");
3 mListView.addHeaderView(mButton);
4  
5 Button mButton2 = new Button(this);
6 mButton2.setText("this is the footer");
7 mListView.addFooterView(mButton2);


此段代码的功能为ListView添加两个按钮作为header和footer,并在按钮上显示提示性的文字。

之后对布局文件中的两个按钮添加onClick事件:


01 public void onDrawSelectorOnTop(View v) {
02 mListView.setSelector(R.drawable.selector_on_top);
03 mListView.setDrawSelectorOnTop(true);
04  
05 }
06  
07 public void onUseSelectorAsBackground(View V) {
08 mListView.setSelector(R.drawable.selector_as_background);
09 mListView.setDrawSelectorOnTop(false);
10  
11 }
   


在布局文件中,分别将两个按钮的onClick属性设置为对应的函数名:


1 android:onClick="onDrawSelectorOnTop"
2 android:onClick="onUseSelectorAsBackground" />


在public void onDrawSelectorOnTop(View v) 中,将ListView的Selector设置为drawable文件夹下的selector_on_top.xml文件,selector_on_top.xml文件的内容如下:


01 <?xml version="1.0" encoding="utf-8"?>
02 <selector xmlns:android="http://schemas.android.com/apk/res/android" >
03 <item
04 android:state_pressed="true"
05 android:drawable="@drawable/list_selector_on_top_pressed" />
06  
07 <item
08 android:state_focused="true"
09 android:drawable="@drawable/list_selector_on_top_focused" />
10  
11 <item
12 android:drawable="@android:color/transparent" />
13  
14 </selector>


在public void onUseSelectorAsBackground(View V) 中,将ListView的Selector设置为drawable文件夹下的selector_as_background.xml文件,selector_as_background.xml文件的内容如下:


01 <?xml version="1.0" encoding="utf-8"?>
02 <selector xmlns:android="http://schemas.android.com/apk/res/android" >
03 <item
04 android:state_pressed="true"
05 android:drawable="@drawable/list_selector_as_background_pressed" />
06  
07 <item
08 android:state_focused="true"
09 android:drawable="@drawable/list_selector_as_background_focused" />
10  
11 <item
12 android:drawable="@android:color/transparent" />
13  
14 </selector>


为ListView添加divider的代码如下:


1 android:divider="#efefef"
2 android:dividerHeight="2dp"


2) Demo2


Demo2的作用主要是验证ListView的transcriptMode和stackFromBottom属性。实现的功能为用户从编辑框输入文字,点击回车按钮后,文字自动添加到ListView的底部,跟短信应用的效果非常相似。主要参考android提供API Demo中的list12。


JAVA代码如下:


01 package com.devdiv.test.listviewtest8;
02  
03 import java.util.ArrayList;
04  
05 import android.app.ListActivity;
06 import android.os.Bundle;
07 import android.view.KeyEvent;
08 import android.view.View;
09 import android.view.View.OnClickListener;
10 import android.view.View.OnKeyListener;
11 import android.widget.ArrayAdapter;
12 import android.widget.EditText;
13 import android.widget.ListView;
14  
15 public class ListViewTest8Activity extends ListActivity {
16  
17 private EditText mEditText;
18  
19 private ArrayAdapter<String> mAdapter;
20  
21 private ArrayList<String> mStrings = new ArrayList<String>();
22  
23 private ListView mListView;
24  
25 /** Called when the activity is first created. */
26 @Override
27 public void onCreate(Bundle savedInstanceState) {
28 super.onCreate(savedInstanceState);
29 setContentView(R.layout.main);
30  
31 mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mStrings);
32  
33 setListAdapter(mAdapter);
34  
35 mEditText = (EditText) findViewById(R.id.userText);
36  
37 mEditText.setOnClickListener(new OnClickListener() {
38  
39 @Override
40 public void onClick(View v) {
41 // TODO Auto-generated method stub
42 submitText();
43  
44 }
45 });
46 mEditText.setOnKeyListener(new OnKeyListener() {
47  
48 @Override
49 public boolean onKey(View v, int keyCode, KeyEvent event) {
50 // TODO Auto-generated method stub
51 if (event.getAction() == KeyEvent.ACTION_DOWN) {
52 switch (keyCode) {
53 case KeyEvent.KEYCODE_DPAD_CENTER:
54 case KeyEvent.KEYCODE_ENTER:
55 submitText();
56 return true;
57 }
58 }
59 return false;
60 }
61 });
62 }
63  
64 public void submitText() {
65 String mString = mEditText.getText().toString();
66 mStrings.add(mString);
67 mEditText.setText(null);
68 mAdapter.notifyDataSetChanged();
69  
70 }
71 }


布局文件main.xml的内容如下:


01 <?xml version="1.0" encoding="utf-8"?>
02  
03 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
04 android:orientation="vertical"
05 android:layout_width="fill_parent"
06 android:layout_height="fill_parent"
07 android:paddingLeft="8dip"
08 android:paddingRight="8dip">
09  
10 <ListView android:id="@android:id/list"
11 android:layout_width="fill_parent"
12 android:layout_height="0dip"
13 android:layout_weight="1"
14 android:stackFromBottom="true"
15 android:transcriptMode="normal"/>
16  
17 <EditText android:id="@+id/userText"
18 android:layout_width="fill_parent"
19 android:layout_height="wrap_content" />
20  
21 </LinearLayout>


其中,transcriptMode和stackFromBottom属性设置为:


1 android:stackFromBottom="true"
2 android:transcriptMode="normal"/>


在submitText()方法中,提交和刷新数据,采用notifyDataSetChanged()的方式。代码如下:


1 public void submitText() {
2 String mString = mEditText.getText().toString();
3 mStrings.add(mString);
4 mEditText.setText(null);
5 mAdapter.notifyDataSetChanged();
6  
7 }


三 运行效果


1) Demo1

QQ截图20120514151439.png


图2 ListView中的header


QQ截图20120514151453.png


图3  ListView中的footer


QQ截图20120514151511.png


图4  点击“Draw selector on top”按钮后Item选中时的效果


QQ截图20120514151519.png


图5 点击“Draw selector as background”按钮后item选中的效果


2) Demo2


QQ截图20120514152826.png


http://www.devdiv.com/Android-listview_-thread-124257-1-1.html


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值