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

http://ysl-paradise.blogspot.com/2008/12/listview.html

 

 

 

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

  1. public class ArrayAdapter<T> extends BaseAdapter implements Filterable {  
  2.  ...  
  3.  public Filter getFilter() {  
  4.   if (mFilter == null) {  
  5.    mFilter = new ArrayFilter();  
  6.   }  
  7.   return mFilter;  
  8.  }  
  9.  ...  
  10.  private class ArrayFilter extends Filter {  
  11.   @Override  
  12.   protected FilterResults performFiltering(CharSequence prefix) {  
  13.    FilterResults results = new FilterResults();  
  14.   
  15.    if (mOriginalValues == null) {  
  16.     synchronized (mLock) {  
  17.      mOriginalValues = new ArrayList<T>(mObjects);  
  18.     }  
  19.    }  
  20.   
  21.    if (prefix == null || prefix.length() == 0) {  
  22.     synchronized (mLock) {  
  23.      ArrayList<T> list = new ArrayList<T>(mOriginalValues);  
  24.      results.values = list;  
  25.      results.count = list.size();  
  26.     }  
  27.    } else {  
  28.     String prefixString = prefix.toString().toLowerCase();  
  29.   
  30.     final ArrayList<T> values = mOriginalValues;  
  31.     final int count = values.size();  
  32.   
  33.     final ArrayList<T> newValues = new ArrayList<T>(count);  
  34.   
  35.     for (int i = 0; i < count; i++) {  
  36.      final T value = values.get(i);  
  37.      final String valueText = value.toString().toLowerCase();  
  38.   
  39.      // First match against the whole, non-splitted value  
  40.      if (valueText.startsWith(prefixString)) {  
  41.       newValues.add(value);  
  42.      } else {  
  43.       final String[] words = valueText.split(" ");  
  44.       final int wordCount = words.length;  
  45.   
  46.       for (int k = 0; k < wordCount; k++) {  
  47.        if (words[k].startsWith(prefixString)) {  
  48.         newValues.add(value);  
  49.         break;  
  50.        }  
  51.       }  
  52.      }  
  53.     }  
  54.   
  55.     results.values = newValues;  
  56.     results.count = newValues.size();  
  57.    }  
  58.   
  59.    return results;  
  60.   }  
  61.   
  62.   @Override  
  63.   protected void publishResults(CharSequence constraint, FilterResults results) {  
  64.    //noinspection unchecked  
  65.    mObjects = (List<T>) results.values;  
  66.    if (results.count > 0) {  
  67.     notifyDataSetChanged();  
  68.    } else {  
  69.     notifyDataSetInvalidated();  
  70.    }  
  71.   }  
  72.  }  
  73.  ...  
  74. }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值