顯示具有 ListView 標籤的文章。 顯示所有文章
顯示具有 ListView 標籤的文章。 顯示所有文章

2011年5月31日 星期二

使用 ListView 元件時該注意的技巧 - II

The tricks when using ListViews - II

使用 ListView 元件時該注意的技巧 - I 中,我們了解到 ListView 常用的技巧。在這一篇中,我們來看看當使用 ListView 時,可能犯的錯誤有哪些。

首先,如果你有寫自己的 ListAdapter,有些人會不曉得在 getView() 中,如何處理傳入的 convertView。

正確的處理方法,應該像底下範例一樣。

如果你不判斷 "if (convertView == null)",每次都呼叫 "sv = new SpeechView(...)",程式當然也會動,不過就會讓 Dalvik 每隔一陣子就瞎忙一通,回收不用的 View objects。這樣的結果,當然也會在使用者捲動時,造成不順的感覺。

第二個最常犯的錯誤就是下面這個例子。

你看出問題在哪了嗎?如果你不知道答案的話,我建議你在自己的 ListAdapter 中的每個函數,都加個 Log.d() 追蹤一下這些函數的執行順序與次數。底下是我某個應用中,所印出來的結果。

整個畫面上,只顯示 7 個項目。怎麼 getView() 被呼叫了那麼多次?

這原因就出在 android:layout_height="wrap_content" 這行描述上。如果將這行改成 android:layout_height="0dip",結果就像下面這樣,getView() 的呼叫次數,完全符合原先的預期。

從這個結果中,我們也看到 getCount() 會被呼叫好幾次。在追蹤過原始碼後,我發現原始碼中並沒有存下 getCount() 的傳回結果。因此這 getCount() 會被呼叫這麼多次,並不是我們的問題。那我們唯一能做的事,就是讓 getCount() 執行的速度越快越好。

如果你有在 ListView 中,套用自己的 ListAdapter。我都會建議你在自己的 ListAdapter 中的每個函數,都加個 Log.d() 追蹤一下這些函數的執行順序與次數,是否都符合你的預期。很簡單的動作,但常會幫你找到不少的問題,分享給你。


繼續閱讀全文...

2011年4月26日 星期二

使用 ListView 元件時該注意的技巧 - I

The tricks when using ListViews - I

綜觀 Android 目前所提供的 UI 元件 (Views),除了 TextView, Button 等元件之外,ListView 應該是最常被使用到的元件之一。

這主要是因為手機多是左右窄、上下長的螢幕,當要顯示很多資料時,垂直捲動會比水平捲動來得容易操作許多。另外,為了便利使用者能快速消化你所呈現的資料,你必須將資料以較為有系統與組織的方式呈現。而用 ListView 來以條列式的方式呈現你的資料,就是手機應用的最好選擇。

如果你有寫過 Android 應用,我想你一定有用過 ListView。不過,你對 ListView 的了解有多少?你知道使用 ListView 元件時,有哪些該注意的技巧嗎?

ListView 最基本的用法就是透過 ArrayAdapter,直接顯示文字的列表。

關於這,你可以閱讀 ListView with default ArrayAdapter 範例,他有很清楚的說明。

如果 ListView 中的每個項目,不是單純的文字,要有些變化時,那你一定要寫自己的 ListAdapter。

API Demos 範例集中,就有 ListView with a custom ListAdapter 這個範例,教你如何寫自己的 ListAdapter。

在上面範例中,雖然已經有處理 convertView 這件事。不過當你的 list item 很複雜 (好幾層的 UI hierarchy 或 Views 很多) 時,每次都呼叫 findViewById() 所浪費的時間,還是會讓捲動變的緩慢。要解決這個問題,這篇 Layout Tricks: Creating Efficient Layouts 會教你如何降低你的 UI hierarchy。另外,你也要看一下 ListView with an efficient ListAdapter 這個範例中所使用的技巧。

如果你的 list item 並不複雜,但捲動時還是很鈍鈍的。那我建議你看一下 ListView with lazy-loading 這個範例。

當你的 ListView 中有成千上百個項目時,除了加 android:fastScrollEnabled="true" 可以方便使用者快速捲動外。更好的解決方式是加上按鍵過濾的功能。如何實現按鍵過濾的功能?你可以參考 如何在 ListView 上加上按鍵過濾的功能 這篇文章。

除了 ListView 之外,別忘了還有 ExpandableListView 可用。尤其當你的資料是兩層式架構時,用 ExpandableListView 是不錯的選擇。

同樣的 API Demos 中已經有好幾個範例了,你可以從 ExpandableListView 這個先看起。

最後,如果你的 ListView 想要有自己的背景圖或顏色。那你要看一下 ListView Backgrounds: An Optimization 這篇文章。解法其實非常簡單,但不說你都不會想到原來 android:cacheColorHint 是用在這個地方。另外一個不說你不知道的用法是 setTranscriptMode()。如果你想要讓 ListView 捲到最後一個項目,那你要用 setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL),相關說明你可以參考 Listview Scroll to the end of the list after updating the list

下次我們再來看,用 ListView 時常犯的錯誤有哪些。


繼續閱讀全文...

2008年12月15日 星期一

如何在 ListView 上加上按鍵過濾的功能

How to add type filter functionality for your ListView widgets?

由於手機螢幕的大小有限,為了要顯示更多的資料,ListView 通常是首選元件。因此,在各式的應用程式中,幾乎都可以見到他的身影。ListView 不只好用,ListView 也提供了各式各樣的客製化功能。我想,他可算是 Android 中,功能最為複雜的元件之一。

今天要分享給大家的,就是如何在 ListView 中 加上按鍵過濾的功能。

想要知道什麼是『按鍵過濾』?想想,當你有上百個聯絡人時,如何快速地找到一個叫 Sam 的人?要知道答案,執行 Contacts 這個程式,按下 's' 鍵,這時你會發現只剩 s 開頭的聯絡人,再按下 a 鍵,幾乎答案就呼之欲出了,因為以 sa 開頭的聯絡人,只剩屈指可數的數目。這種依照你按鍵輸入的文字,來過濾 ListView 所要顯示的內容,就是我這提的『按鍵過濾』功能。

要如何做到這功能?為了要找到解法,我開始翻出 Contacts 的原始碼,仔細研究他是如何做到的。在研讀原始碼的過程中,還意外發現其中還藏了 Android Secret Code 這個東西。試試,在你的 G1 手機上,輸入 *#*#4636#*#* 。嘿嘿,你看到什麼了嗎?用模擬器,是沒用的,一定要實體手機才行。還有更多的 secret code ,我貼在 Android secret code 這篇文章上。有興趣的,自己上去瞧瞧。

好了,言歸正傳。關於要如何做到『按鍵過濾』功能的答案,其實非常簡單,就是對你的 ListView 加上 setTextFilterEnabled(true) ,就可以了。

對你的程式沒效嗎?先別急,這還有個但書,那就是你透過 ListView.setAdapter() 所傳入的 ListAdapter, 一定要實現 Filterable 這個介面才行。目前,ArrayAdapter,CursorAdapter 和 SimpleAdapter 這幾個 Adapter 都有實現 Filterable 這個介面。一般大家常用的是 ArrayAdapter<String> ,那你只要對你的 ListView 加上 setTextFilterEnabled(true) ,應該馬上就有『按鍵過濾』的功能。在 API Demos 程式中,第一個畫面內的 ListView 也有加上這功能。

不過,通常事情都沒這麼簡單。像我的 ListAdapter 就是繼承自 BaseAdapter,做出自己的 Adapter。BaseAdapter 當然沒有實現 Filterable 這個介面。你得自行實現 Filterable 介面所要求的 performFiltering() 和 publishResults() 函式。

如何實現這兩個函式?我在 在 Android 上利用 Google APIs 實現 Google Suggestion 功能 這篇文章中,有提到過。

另外,別忘了,你還有 Android 原始碼可以參考,那是你最好的導師。為了幫助你的了解,我將 platform\framework\base\core\java\android\widget\ArrayAdapter.java 原始碼中,關於如何實現 Filterable 介面的部份,貼出來,分享給你。


繼續閱讀全文...