2013-02-02 107 views
78

我已經創造了Android的列表視圖,我想添加列表上方編輯文本,並且當用戶輸入文本列表將被過濾根據用戶輸入列表視圖篩選的Android

誰能告訴我請,如果有一種方法來過濾Android中的列表適配器?

+1

嗨嘗試這個例子[示例一](https://rakhi577.wordpress.com/2012/06/26/buttons-on-list-view-with-easy-searching-in-android/)和第二個一個[示例2](http://stackoverflow.com/questions/2463777/autocompletetextview-with-custom-list-how-to-set-up-onitemclicklistener)我已經實現了基於這個教程的相同..我希望這將幫助您 – Pragnani

+0

+1升masr ..... –

+4

最佳答案只是沒有提供足夠的信息給我。 [這個答案](http://stackoverflow.com/a/24771174/11912)到一個類似的問題有更多的上下文,是完全足夠的信息,讓我整理出來。 –

回答

122

是的。 在其aml佈局文件中的列表視圖頂部添加一個EditText。 而在你的活動/片段..

lv = (ListView) findViewById(R.id.list_view); 
    inputSearch = (EditText) findViewById(R.id.inputSearch); 

// Adding items to listview 
adapter = new ArrayAdapter<String>(this, R.layout.list_item, R.id.product_name, products); 
lv.setAdapter(adapter);  
inputSearch.addTextChangedListener(new TextWatcher() { 

    @Override 
    public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) { 
     // When user changed the Text 
     MainActivity.this.adapter.getFilter().filter(cs); 
    } 

    @Override 
    public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { } 

    @Override 
    public void afterTextChanged(Editable arg0) {} 
}); 

這裏的基本是一個OnTextChangeListener添加到您編輯文本和其回調方法裏面將過濾器應用於您的ListView的適配器。

編輯

爲了讓過濾器,以自定義BaseAdapter你「會需要實現可篩選接口。

class CustomAdapter extends BaseAdapter implements Filterable { 

    public View getView(){ 
    ... 
    } 
    public Integer getCount() 
    { 
    ... 
    } 

    @Override 
    public Filter getFilter() { 

     Filter filter = new Filter() { 

      @SuppressWarnings("unchecked") 
      @Override 
      protected void publishResults(CharSequence constraint, FilterResults results) { 

       arrayListNames = (List<String>) results.values; 
       notifyDataSetChanged(); 
      } 

      @Override 
      protected FilterResults performFiltering(CharSequence constraint) { 

       FilterResults results = new FilterResults(); 
       ArrayList<String> FilteredArrayNames = new ArrayList<String>(); 

       // perform your search here using the searchConstraint String. 

       constraint = constraint.toString().toLowerCase(); 
       for (int i = 0; i < mDatabaseOfNames.size(); i++) { 
        String dataNames = mDatabaseOfNames.get(i); 
        if (dataNames.toLowerCase().startsWith(constraint.toString())) { 
         FilteredArrayNames.add(dataNames); 
        } 
       } 

       results.count = FilteredArrayNames.size(); 
       results.values = FilteredArrayNames; 
       Log.e("VALUES", results.values.toString()); 

       return results; 
      } 
     }; 

     return filter; 
    } 
} 

perfromFiltering()你需要做的實際比較將搜索查詢轉換爲數據庫中的值,並將結果傳遞給publishResults()方法

+0

我已經創建了一個自定義適配器,它擴展了BaseAdapter並在其中定義了我的對象的向量,該對象將顯示在列表中,當我嘗試使用上述代碼時,我無法在適配器中找到getFilter方法,你請告訴我,如果我必須實現任何接口? –

+0

在BaseAdapter的情況下過濾數據有點棘手。您將不得不實施可執行界面來實現BaseAdapter。您將有getFilter()方法,並且在其中您必須實現兩個回調方法才能使用; void publishResults()和FilterResults performFiltering(CharSequence約束)。 –

+0

你能用一個簡單的例子來支持嗎? –

9

實現您的適配器可篩選:

public class vJournalAdapter extends ArrayAdapter<JournalModel> implements Filterable{ 
private ArrayList<JournalModel> items; 
private Context mContext; 
.... 

然後創建過濾器類:

private class JournalFilter extends Filter{ 

    @Override 
    protected FilterResults performFiltering(CharSequence constraint) { 
     FilterResults result = new FilterResults(); 
     List<JournalModel> allJournals = getAllJournals(); 
     if(constraint == null || constraint.length() == 0){ 

      result.values = allJournals; 
      result.count = allJournals.size(); 
     }else{ 
      ArrayList<JournalModel> filteredList = new ArrayList<JournalModel>(); 
      for(JournalModel j: allJournals){ 
       if(j.source.title.contains(constraint)) 
        filteredList.add(j); 
      } 
      result.values = filteredList; 
      result.count = filteredList.size(); 
     } 

     return result; 
    } 
    @SuppressWarnings("unchecked") 
    @Override 
    protected void publishResults(CharSequence constraint, FilterResults results) { 
     if (results.count == 0) { 
      notifyDataSetInvalidated(); 
     } else { 
      items = (ArrayList<JournalModel>) results.values; 
      notifyDataSetChanged(); 
     } 
    } 

} 

這樣,你的適配器是可篩選,你可以通過過濾器項目適配器的過濾器,做的工作。 我希望這會有所幫助。

1

如果有人對此主題感興趣,我發現過濾列表的最佳方法是創建一個通用的Filter類,並將其與Java老派SDK包中包含的一些基本反射/泛型技術結合使用。下面是我所做的:

public class GenericListFilter<T> extends Filter { 

    /** 
    * Copycat constructor 
    * @param list the original list to be used 
    */ 
    public GenericListFilter (List<T> list, String reflectMethodName, ArrayAdapter<T> adapter) { 
     super(); 

     mInternalList = new ArrayList<>(list); 
     mAdapterUsed = adapter; 

     try { 
      ParameterizedType stringListType = (ParameterizedType) 
        getClass().getField("mInternalList").getGenericType(); 
      mCompairMethod = 
        stringListType.getActualTypeArguments()[0].getClass().getMethod(reflectMethodName); 
     } 
     catch (Exception ex) { 
      Log.w("GenericListFilter", ex.getMessage(), ex); 

      try { 
       if (mInternalList.size() > 0) { 
        T type = mInternalList.get(0); 
        mCompairMethod = type.getClass().getMethod(reflectMethodName); 
       } 
      } 
      catch (Exception e) { 
       Log.e("GenericListFilter", e.getMessage(), e); 
      } 

     } 
    } 

    /** 
    * Let's filter the data with the given constraint 
    * @param constraint 
    * @return 
    */ 
    @Override protected FilterResults performFiltering(CharSequence constraint) { 
     FilterResults results = new FilterResults(); 
     List<T> filteredContents = new ArrayList<>(); 

     if (constraint.length() > 0) { 
      try { 
       for (T obj : mInternalList) { 
        String result = (String) mCompairMethod.invoke(obj); 
        if (result.toLowerCase().startsWith(constraint.toString().toLowerCase())) { 
         filteredContents.add(obj); 
        } 
       } 
      } 
      catch (Exception ex) { 
       Log.e("GenericListFilter", ex.getMessage(), ex); 
      } 
     } 
     else { 
      filteredContents.addAll(mInternalList); 
     } 

     results.values = filteredContents; 
     results.count = filteredContents.size(); 
     return results; 
    } 

    /** 
    * Publish the filtering adapter list 
    * @param constraint 
    * @param results 
    */ 
    @Override protected void publishResults(CharSequence constraint, FilterResults results) { 
     mAdapterUsed.clear(); 
     mAdapterUsed.addAll((List<T>) results.values); 

     if (results.count == 0) { 
      mAdapterUsed.notifyDataSetInvalidated(); 
     } 
     else { 
      mAdapterUsed.notifyDataSetChanged(); 
     } 
    } 

    // class properties 
    private ArrayAdapter<T> mAdapterUsed; 
    private List<T> mInternalList; 
    private Method mCompairMethod; 
} 

而且事後,你需要做的唯一的事情就是創建過濾器作爲成員類(有可能在視圖的「的onCreate」)通過你的適配器參考,您的列表,以及被調用的方法過濾:

this.mFilter = new GenericFilter<MyObjectBean> (list, "getName", adapter); 

現在唯一缺少的,就是要覆蓋「用getFilter」方法的適配器類:

@Override public Filter getFilter() { 
    return MyViewClass.this.mFilter; 
} 

全部完成!你應該成功過濾你的列表 - 當然,你也應該實現你的過濾器算法描述你的需要的最佳方式,下面的代碼只是一個例子。。希望它有幫助,保重。

+0

我不知道有關android,但我記得被告知儘量避免反射,如果可能在C#因爲它是相當資源密集型(我通常在Windows移動應用程序所以這可能是一個問題),這是否適用於Android?或者反射與構建沒有泛型的實際類相同的效果?我正在考慮創建一個可過濾的模板,並添加用作參數的類和方法 – Cruces

+0

是的,你是對的。這同樣適用於這裏,反射給程序處理一個權重,但在這種情況下,它是一個非常簡單的使用它,並且因爲我們使用通用/模板表示法,它也有助於編譯器。祝你好運! – jbrios777