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 介面的部份,貼出來,分享給你。

3 則留言:

Gitaman 提到...

您好,我現在遇到一個問題,就是我想利用另一個EditText來做為輸入過濾文字的輸入元件,並且將原本黑色顯示使用者輸入過濾文字的popup視窗隱藏掉。

不知該如何將這popup黑色的視窗隱藏掉。
目前可以利用ListView.setFilterText(text),將EditText內的文字填入,做為過濾的條件,只不過這樣畫面上看來很怪,在EditText上打的過濾文字又會有另一個pop視窗顯示,不知道是否有解法可解決這問題,謝謝囉!

samlu 提到...

目前應該沒相對應的 API 可用。我會建議你,直接讀 Android 的原始碼,應該會有收穫的。

Gitaman 提到...

您好,這問題我已經解決了,經由我這幾天查詢以及trace android source code的結果,利用setFilterText一定會出現這個POPUP視窗。

解決方法如下:
假設我ListView所使用的為MyAdapter, 呼叫MyAdapter.getFilter.filter()即可,利用這方法可以trigger filter,而且不會出現popup視窗。MyAdapter必須implement Filterable,如同您文章所介紹的…

謝謝!

張貼留言