2011-04-25 30 views
62

我試圖實現使用自定義對象適配器的ListView的篩選,但找不到任何有用的示例。包含的代碼非常簡化,所以請記住,我不能使用常規的ArrayAdapter。 我有一個EditText在ListView上方,當用戶在EditText小部件中輸入文本時,我想通過EditText中寫入的文本過濾ListView。 任何建議將不勝感激!使用自定義(對象)適配器篩選ListView

這裏是從活動類中的片段:

public class management_objects extends Activity { 

private static List<User> UserList; 
private EfficientAdapter adapter = null; 
private ListView objectListView = null; 
private EditText SearchText = null; 

private static class EfficientAdapter extends BaseAdapter implements Filterable{ 
    private LayoutInflater mInflater; 

    public EfficientAdapter(Context context) { 
     mInflater = LayoutInflater.from(context); 
    } 

    public int getCount() { 
     return UserList.size(); 
    } 

    public Object getItem(int position) { 
     return position; 
    } 

    public long getItemId(int position) { 
     return position; 
    } 

    public View getView(int position, View convertView, ViewGroup parent) { 
     ViewHolder holder; 
     if (convertView == null) { 
      convertView = mInflater.inflate(R.layout.imagelayout_2lines, null); 
      holder = new ViewHolder(); 
      holder.text = (TextView) convertView.findViewById(R.id.managementObjectText); 
      holder.subtext = (TextView) convertView.findViewById(R.id.managementObjectSubText); 
      holder.icon = (ImageView) convertView.findViewById(R.id.managementObjectIcon); 
      convertView.setTag(holder); 
     } 
     else { 
      holder = (ViewHolder) convertView.getTag(); 
     } 

     holder.text.setText(UserList.get(position).getFirstName()); 
     holder.subtext.setText(UserList.get(position).getLastName()); 
     holder.icon.setImageResource(R.drawable.user); 

     return convertView; 
    } 

    static class ViewHolder { 
     TextView text; 
     TextView subtext; 
     ImageView icon; 
    } 

    @Override 
    public Filter getFilter() { 
     return null; 
    } 
} 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.adobjectlist); 
    Bundle extras = getIntent().getExtras(); 

    SearchText = (EditText) findViewById(R.id.SearchBox);  
    SearchText.addTextChangedListener(filterTextWatcher); 

    objectListView = (ListView) findViewById(R.id.ObjectList); 
    objectListView.setOnItemClickListener(Item_Click); 
    adapter = new EfficientAdapter(this); 
    ComputerName = extras.getString("COMPUTER_NAME"); 

    //Get User list from webservice 
    ShowUsers(); 
} 

這裏是用戶等級:

public class User { 
    private int UserId; 
    private String FirstName; 
    private String LastName; 

    public int getUserId() { 
     return UserId; 
    } 
    public void setUserId(int UserId) { 
     this.UserId = UserId; 
    } 
    public String getFirstName() { 
     return FirstName; 
    } 
    public void setFirstName(String FirstName) { 
     this.FirstName = FirstName; 
    } 
    public String getLastName() { 
     return LastName; 
    } 
    public void setLastName(String LastName) { 
     this.LastName = LastName; 
    } 
} 

回答

70

你需要做幾件事情:

1)在你的活動,請在您的EditText上註冊一個包含用戶輸入值的文本更改偵聽器:

mSearchValue.addTextChangedListener(searchTextWatcher);

2)創建searchTextWatcher並將它做一些事情:

private TextWatcher searchTextWatcher = new TextWatcher() { 
    @Override 
     public void onTextChanged(CharSequence s, int start, int before, int count) { 
      // ignore 
     } 

     @Override 
     public void beforeTextChanged(CharSequence s, int start, int count, int after) { 
      // ignore 
     } 

     @Override 
     public void afterTextChanged(Editable s) { 
      Log.d(Constants.TAG, "*** Search value changed: " + s.toString()); 
      adapter.getFilter().filter(s.toString()); 
     } 
    }; 

3)在您的自定義適配器覆蓋用getFilter(),並把它過濾結果,並通知該數據集已經改變了列表視圖。

@Override 
    public Filter getFilter() { 
     return new Filter() { 
      @SuppressWarnings("unchecked") 
      @Override 
      protected void publishResults(CharSequence constraint, FilterResults results) { 
       Log.d(Constants.TAG, "**** PUBLISHING RESULTS for: " + constraint); 
       myData = (List<MyDataType>) results.values; 
       MyCustomAdapter.this.notifyDataSetChanged(); 
      } 

      @Override 
      protected FilterResults performFiltering(CharSequence constraint) { 
       Log.d(Constants.TAG, "**** PERFORM FILTERING for: " + constraint); 
       List<MyDataType> filteredResults = getFilteredResults(constraint); 

       FilterResults results = new FilterResults(); 
       results.values = filteredResults; 

       return results; 
      } 
     }; 
    } 
+4

爲什麼你說在3)「覆蓋」? BaseAdapter沒有getFilter()。 – Ixx 2012-05-02 11:31:02

+4

良好的捕獲 - 不需要。我的自定義Adapter類(實際上是從AmazingListView開源小部件中的AmazingAdapter繼承而來)實現了需要getFilter()的android.widget.Filterable接口。 – DustinB 2012-05-03 14:56:29

+24

[本教程](http://www.survivingwithandroid.com/2012/10/android-listview-custom-filter-and.html)幫助了我。答案有些不清楚,或者我沒有足夠的注意力去閱讀。 – Sufian 2013-03-26 10:53:53

16

這裏一個有趣的例子

public Filter getFilter() { 
    return new Filter() { 

     @Override 
     protected FilterResults performFiltering(CharSequence constraint) { 
      final FilterResults oReturn = new FilterResults(); 
      final ArrayList<station> results = new ArrayList<station>(); 
      if (orig == null) 
       orig = items; 
      if (constraint != null) { 
       if (orig != null && orig.size() > 0) { 
        for (final station g : orig) { 
         if (g.getName().toLowerCase() 
           .contains(constraint.toString())) 
          results.add(g); 
        } 
       } 
       oReturn.values = results; 
      } 
      return oReturn; 
     } 

     @SuppressWarnings("unchecked") 
     @Override 
     protected void publishResults(CharSequence constraint, 
       FilterResults results) { 
      items = (ArrayList<station>) results.values; 
      notifyDataSetChanged(); 
     } 
    }; 
} 

public void notifyDataSetChanged() { 
    super.notifyDataSetChanged(); 
    notifyChanged = true; 
} 
+1

使用ORIG變量保存初始實例的出色方法。它運作良好,謝謝。 – radhoo 2013-06-03 18:46:59

+0

非常感謝,這正是我所需要的:D +1! – Tenaciousd93 2014-04-22 10:12:07

2

對於那些誰不需要Filterable接口,還有一個更簡單的解決方案。在其他解決方案失敗的情況下,這也正確處理notifyDataSetChanged()。請注意,您需要將getArray()函數添加到BaseAdapter,該函數僅返回傳遞給構造函數的數組對象。

public abstract class BaseFilterAdapter<T> extends BaseAdapter<T> { 

    private List<T> original; 
    private String lastFilter; 

    public BaseFilterAdapter(Context context, List<T> array) { 
     super(context, new LinkedList<T>()); 
     original = array; 
     filter(""); 
    } 

    protected abstract Boolean predicate(T element, String filter); 

    public void filter(String filter) { 
     lastFilter = filter; 
     super.getArray().clear(); 
     for (T element : original) 
      if (predicate(element, filter)) 
       super.getArray().add(element); 
     super.notifyDataSetChanged(); 
    } 

    @Override 
    public List<T> getArray() { 
     return original; 
    } 

    @Override 
    public void notifyDataSetChanged() { 
     filter(lastFilter); 
    } 
} 
+0

沒有getArray方法在我的BaseAdapter類中重寫。 – 2017-12-12 14:04:35

1

在您的基類中添加toString覆蓋。例如

@Override 
public String toString() { 
    return this.name; 
} 

上面的列表使您的List成爲字符串列表。所以你可以使用:

your_edit_text.addTextChangedListener(new TextWatcher() { 

    @Override 
    public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { 
     YourActivity.this.YourAdapter.getFilter().filter(arg0); 
    } 

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

    @Override 
    public void afterTextChanged(Editable arg0) {  
    } 
}); 
相關問題