2010-03-25 138 views
13

我有一個ListView連接到ArrayAdapter,其中Artist是我的一個簡單類,它只有一個id和一個名稱。如何使用ArrayAdapter爲ListView編寫自定義過濾器

現在我想過濾的ListView,所以我呼籲:

artistAdapter.getFilter().filter("bla", new Filter.FilterListener() { 
    public void onFilterComplete(int count) { 
     Log.d(Config.LOG_TAG, "filter complete! count: " + count); // returns 8 
     Log.d(Config.LOG_TAG, "adapter count: " + artistAdapter.getCount()); // return 1150 
    } 
}); 

第一調試語句打印的8計數那是corrent計數以「喇嘛」開始時listItems但適配器沒有得到它。第二個調試語句打印一個計數1150項。這是列表中完整的項目數量。

因此,某種程度上,過濾器不會告訴適配器它已經過濾了底層數據。

我現在想知道:我是否在我的適配器中編寫了代碼,以便從過濾器獲取更新?我是否必須編寫自定義過濾器?我需要做什麼?

+0

http://stackoverflow.com/questions/2718202/custom-filtering-in-android-using-arrayadapter - 看起來似乎是回答你的問題 – stealthcopter 2010-09-09 02:23:53

+0

@Anton:甲肝ü解決it.Please回覆.. ....... – 2012-06-22 11:34:06

回答

1

我認爲你可以在方法onFilterComplete中使用notifyDataSetChanged();

26

其實

我注意到,我應該用'originalItems名單打造performFiltering新過濾一個已經。

這將修復您在更改過濾器中的文本時看到的任何問題。例如。你搜索'麪包',然後退格到'B',你應該看到所有'B'。在我原來的文章中,你不會有。

private class GlycaemicIndexItemAdapter extends ArrayAdapter<GlycaemicIndexItem> { 

    private ArrayList<GlycaemicIndexItem> items; 
    private ArrayList<GlycaemicIndexItem> originalItems = new ArrayList<GlycaemicIndexItem>(); 
    private GlycaemicIndexItemFilter filter; 
    private final Object mLock = new Object(); 

    public GlycaemicIndexItemAdapter(Context context, int textViewResourceId, ArrayList<GlycaemicIndexItem> newItems) { 
      super(context, textViewResourceId, newItems); 
      this.items = newItems; 
      cloneItems(newItems); 
    } 

    protected void cloneItems(ArrayList<GlycaemicIndexItem> items) { 
     for (Iterator iterator = items.iterator(); iterator 
     .hasNext();) { 
      GlycaemicIndexItem gi = (GlycaemicIndexItem) iterator.next(); 
      originalItems.add(gi); 
     } 
    } 

    @Override 
    public int getCount() { 
     synchronized(mLock) { 
      return items!=null ? items.size() : 0; 

    } 

    @Override 
    public GlycaemicIndexItem getItem(int item) { 
     GlycaemicIndexItem gi = null; 
     synchronized(mLock) { 
       gi = items!=null ? items.get(item) : null; 

     } 
     return gi; 
    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
      View v = convertView; 
      if (v == null) { 
       LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
       v = vi.inflate(R.layout.row, null); 
      } 

      GlycaemicIndexItem i = null; 
      synchronized(mLock) { 
       i = items.get(position); 
      } 

      if (i != null) { 
        TextView tt = (TextView) v.findViewById(R.id.rowText); 
        TextView bt = (TextView) v.findViewById(R.id.rowText2); 
        if (tt != null) { 
          tt.setText("Name: "+i.getName());        
        } 
        if(bt != null){ 
          bt.setText("GI Value: " + i.getGlycaemicIndex()); 
        } 
      } 
      return v; 
    } 
    /** 
    * Implementing the Filterable interface. 
    */ 
    public Filter getFilter() { 
     if (filter == null) { 
      filter = new GlycaemicIndexItemFilter(); 
     } 
     return filter; 
    } 

    /** 
    * Custom Filter implementation for the items adapter. 
    * 
    */ 
    private class GlycaemicIndexItemFilter extends Filter { 
     protected FilterResults performFiltering(CharSequence prefix) { 
      // Initiate our results object 
      FilterResults results = new FilterResults(); 

      // No prefix is sent to filter by so we're going to send back the original array 
      if (prefix == null || prefix.length() == 0) { 
       synchronized (mLock) { 
        results.values = originalItems; 
        results.count = originalItems.size(); 
       } 
      } else { 
       synchronized(mLock) { 
         // Compare lower case strings 
        String prefixString = prefix.toString().toLowerCase(); 
        final ArrayList<GlycaemicIndexItem> filteredItems = new ArrayList<GlycaemicIndexItem>(); 
        // Local to here so we're not changing actual array 
        final ArrayList<GlycaemicIndexItem> localItems = new ArrayList<GlycaemicIndexItem>(); 
        localItems.addAll(originalItems); 
        final int count = localItems.size(); 

        for (int i = 0; i < count; i++) { 
         final GlycaemicIndexItem item = localItems.get(i); 
         final String itemName = item.getName().toString().toLowerCase(); 

         // First match against the whole, non-splitted value 
         if (itemName.startsWith(prefixString)) { 
          filteredItems.add(item); 
         } else {} /* This is option and taken from the source of ArrayAdapter 
          final String[] words = itemName.split(" "); 
          final int wordCount = words.length; 

          for (int k = 0; k < wordCount; k++) { 
           if (words[k].startsWith(prefixString)) { 
            newItems.add(item); 
            break; 
           } 
          } 
         } */ 
        } 

        // Set and return 
        results.values = filteredItems; 
        results.count = filteredItems.size(); 
       }//end synchronized 
      } 

      return results; 
     } 

     @SuppressWarnings("unchecked") 
     @Override 
     protected void publishResults(CharSequence prefix, FilterResults results) { 
      //noinspection unchecked 
      synchronized(mLock) { 
       final ArrayList<GlycaemicIndexItem> localItems = (ArrayList<GlycaemicIndexItem>) results.values; 
       notifyDataSetChanged(); 
       clear(); 
       //Add the items back in 
       for (Iterator iterator = localItems.iterator(); iterator 
         .hasNext();) { 
        GlycaemicIndexItem gi = (GlycaemicIndexItem) iterator.next(); 
        add(gi); 
       } 
      }//end synchronized 
     } 
    } 
} 

基本上我建立一個健康和營養的應用程序和一個屏幕將具有基於血糖/血糖指數的項目清單。我希望用戶能夠輸入和屏幕自動篩選。現在,如果您只使用字符串,則可以免費進行自動過濾。我不是,我有我自己的自定義類GlycaemicIndexItem它具有屬性。我需要提供自己的過濾功能,以確保在用戶輸入時更新屏幕上繪製的列表。

當前屏幕是一個簡單的ListActivity,帶有一個ListView和一個EditText(用戶輸入)。我們將在此EditText上附加一個TextWatcher,以確保我們收到更新通知。這意味着它應該適用於所有設備,無論用戶在硬鍵還是軟鍵盤上打字(我有HTC DesireZ和舊G1)。

下面是屏/活動佈局XML(可有人告訴我如何將XML代碼粘貼到這裏,因爲當我嘗試使用代碼塊的XML沒有得到粘貼/正常顯示,但解釋):

layout for the activity - giatoz.xml

由於我們要顯示我們在自定義樣式行,我們也有該行本身的佈局xml文件: Row xml file

這裏是整個活動本身的代碼。從ListActivity擴展而來,這個類有一個充當適配器的內部類,它從ArrayAdapter擴展而來。這是在Activity的onCreate中實例化的,現在傳遞了一個簡單的字符串列表。請注意它是如何在第39-40行創建的。我們對行的特殊佈局與物品列表一起傳入。

填充自定義行的關鍵在於適配器的方法getView

我們的適配器類也有它自己的內部類,名爲GlycaemicIndexItemFilter,它可以在用戶輸入時完成工作。我們的過濾器通過使用TextWatcher及其方法afterTextChanged在第43-44行綁定到我們的EditText。第47行是我們如何實現過濾的線索。我們在過濾器對象上調用過濾器。我們的過濾器是在我們第一次調用getFilter時創建的,第148-149行。

package com.tilleytech.android.myhealthylife; 

    import java.util.ArrayList; 
    import java.util.Iterator; 

    import android.app.ListActivity; 
     import android.content.Context; 
    import android.content.res.Resources; 
    import android.os.Bundle; 
    import android.text.Editable; 
     import android.text.TextWatcher; 
     import android.view.LayoutInflater; 
     import android.view.View; 
     import android.view.ViewGroup; 
     import android.widget.ArrayAdapter; 
     import android.widget.EditText; 
     import android.widget.Filter; 
     import android.widget.ListView; 
     import android.widget.TextView; 


     public class GlycaemicIndexAtoZActivity extends ListActivity { 
      /** Called when the activity is first created. */ 
     private GlycaemicIndexItemAdapter giAdapter; 
     private TextWatcher filterTextWatcher; 
     private EditText filterText = null; 

     @Override 
     public void onCreate(Bundle savedInstanceState) { 

     super.onCreate(savedInstanceState); 
     setContentView(R.layout.giatoz);    

     ListView lv = getListView(); 
     lv.setTextFilterEnabled(true); 
     // By using setAdapter method in listview we an add string array in list. 
     ArrayList<GlycaemicIndexItem> list = getListItems(); 

     giAdapter = new GlycaemicIndexItemAdapter(this, R.layout.row, list); 
     giAdapter.notifyDataSetChanged(); 
     setListAdapter(giAdapter); 

     filterText = (EditText)findViewById(R.id.GI_AtoZSearchEditText); 
     filterTextWatcher = new TextWatcher() { 

      public void afterTextChanged(Editable s) { 
       giAdapter.getFilter().filter(s); //Filter from my adapter 
       giAdapter.notifyDataSetChanged(); //Update my view 

      } 

      public void beforeTextChanged(CharSequence s, int start, int count, 
        int after) { 
      } 

      public void onTextChanged(CharSequence s, int start, int before, 
        int count) { 

      } 

     }; 
     filterText.addTextChangedListener(filterTextWatcher); 
    } 

    private ArrayList<GlycaemicIndexItem> getListItems() { 
     ArrayList<GlycaemicIndexItem> result = new ArrayList<GlycaemicIndexItem>(); 

     Resources res = getResources(); 
     //Get our raw strings 
     String[] array = res.getStringArray(R.array.GIList); 
     for (int i = 0; i < array.length; i++) { 
      GlycaemicIndexItem gi = new GlycaemicIndexItem(); 
      gi.setName(array[i]); 
      gi.setGlycaemicIndex(1); 
      result.add(gi); 
     } 

     return result; 
    } 

    private class GlycaemicIndexItemAdapter extends ArrayAdapter<GlycaemicIndexItem> { 

     private ArrayList<GlycaemicIndexItem> items; 
     private ArrayList<GlycaemicIndexItem> originalItems = new ArrayList<GlycaemicIndexItem>(); 
     private GlycaemicIndexItemFilter filter; 
     private final Object mLock = new Object(); 

     public GlycaemicIndexItemAdapter(Context context, int textViewResourceId, ArrayList<GlycaemicIndexItem> newItems) { 
       super(context, textViewResourceId, newItems); 
       this.items = newItems; 
       cloneItems(newItems); 
     } 

     protected void cloneItems(ArrayList<GlycaemicIndexItem> items) { 
      for (Iterator iterator = items.iterator(); iterator 
      .hasNext();) { 
       GlycaemicIndexItem gi = (GlycaemicIndexItem) iterator.next(); 
       originalItems.add(gi); 
      } 
     } 

     @Override 
     public int getCount() { 
      synchronized(mLock) { 
       return items!=null ? items.size() : 0; 
      } 
     } 

     @Override 
     public GlycaemicIndexItem getItem(int item) { 
      GlycaemicIndexItem gi = null; 
      synchronized(mLock) { 
        gi = items!=null ? items.get(item) : null; 

      } 
      return gi; 
     } 

     @Override 
     public View getView(int position, View convertView, ViewGroup parent) { 
       View v = convertView; 
       if (v == null) { 
        LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
        v = vi.inflate(R.layout.row, null); 
       } 

       GlycaemicIndexItem i = null; 
       synchronized(mLock) { 
        i = items.get(position); 
       } 

       if (i != null) { 
         TextView tt = (TextView) v.findViewById(R.id.rowText); 
         TextView bt = (TextView) v.findViewById(R.id.rowText2); 
         if (tt != null) { 
           tt.setText("Name: "+i.getName());        
         } 
         if(bt != null){ 
           bt.setText("GI Value: " + i.getGlycaemicIndex()); 
         } 
       } 
       return v; 
     } 
     /** 
     * Implementing the Filterable interface. 
     */ 
     public Filter getFilter() { 
      if (filter == null) { 
       filter = new GlycaemicIndexItemFilter(); 
      } 
      return filter; 
     } 

     /** 
     * Custom Filter implementation for the items adapter. 
     * 
     */ 
     private class GlycaemicIndexItemFilter extends Filter { 
      protected FilterResults performFiltering(CharSequence prefix) { 
       // Initiate our results object 
       FilterResults results = new FilterResults(); 

       // No prefix is sent to filter by so we're going to send back the original array 
       if (prefix == null || prefix.length() == 0) { 
        synchronized (mLock) { 
         results.values = originalItems; 
         results.count = originalItems.size(); 
        } 
       } else { 
        synchronized(mLock) { 
          // Compare lower case strings 
         String prefixString = prefix.toString().toLowerCase(); 
         final ArrayList<GlycaemicIndexItem> filteredItems = new ArrayList<GlycaemicIndexItem>(); 
         // Local to here so we're not changing actual array 
         final ArrayList<GlycaemicIndexItem> localItems = new ArrayList<GlycaemicIndexItem>(); 
         localItems.addAll(originalItems); 
         final int count = localItems.size(); 

         for (int i = 0; i < count; i++) { 
          final GlycaemicIndexItem item = localItems.get(i); 
          final String itemName = item.getName().toString().toLowerCase(); 

          // First match against the whole, non-splitted value 
          if (itemName.startsWith(prefixString)) { 
           filteredItems.add(item); 
          } else {} /* This is option and taken from the source of ArrayAdapter 
           final String[] words = itemName.split(" "); 
           final int wordCount = words.length; 

           for (int k = 0; k < wordCount; k++) { 
            if (words[k].startsWith(prefixString)) { 
             newItems.add(item); 
             break; 
            } 
           } 
          } */ 
         } 

         // Set and return 
         results.values = filteredItems; 
         results.count = filteredItems.size(); 
        }//end synchronized 
       } 

       return results; 
      } 

      @SuppressWarnings("unchecked") 
      @Override 
      protected void publishResults(CharSequence prefix, FilterResults results) { 
       //noinspection unchecked 
       synchronized(mLock) { 
        final ArrayList<GlycaemicIndexItem> localItems = (ArrayList<GlycaemicIndexItem>) results.values; 
        notifyDataSetChanged(); 
        clear(); 
        //Add the items back in 
        for (Iterator iterator = localItems.iterator(); iterator 
          .hasNext();) { 
         GlycaemicIndexItem gi = (GlycaemicIndexItem) iterator.next(); 
         add(gi); 
        } 
       }//end synchronized 
      } 
     } 
    } 
} 
+0

你可以給一個簡單的演示,告訴如何使用它?謝謝 – pengwang 2011-03-23 09:28:09

+0

我問一個問題:http://stackoverflow.com/questions/5404197/listview-filter-mistake你能幫我什麼是我的錯誤 – pengwang 2011-03-23 11:01:18

+0

嗨,我剛剛檢查了你的其他頁面,它看起來像一些人已經幫助你已經。你需要在你的TestFilter類中檢查第33行。這是一個NullPointerException,當您嘗試調用方法或訪問尚未實例化(創建)的類實例(稱爲對象)時,會發生這種情況。 – TilleyTech 2011-03-23 14:34:32

相關問題