Filtern von ListView mit benutzerdefiniertem (Objekt-) Adapter

Ich versuche, die Filterung einer ListView zu implementieren, die einen benutzerdefinierten Objektadapter verwendet, aber ich kann keine nützlichen Beispiele finden. Der mitgelieferte Code ist sehr vereinfacht, also bedenken Sie, dass ich keinen regulären ArrayAdapter verwenden kann. Ich habe einen EditText über der ListView, und wenn der Benutzer Text in das EditText Widget eingibt, möchte ich die ListView nach dem Text filtern, der in EditText geschrieben wurde. Irgendwelche Vorschläge würden sehr geschätzt!

Hier ist das Snippet aus der Aktivitätsklasse:

public class management_objects extends Activity { private static List 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(); } 

Hier ist die Benutzerklasse:

  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; } } 

   

Sie müssen ein paar Dinge tun:

1) Melden Sie sich in Ihrer Aktivität für einen Listener für Textänderungen in Ihrem EditText an, der den Wert enthält, den der Benutzer eingibt:

mSearchValue.addTextChangedListener (searchTextWatcher);

2) Erstelle deinen searchTextWatcher und lass es etwas machen:

 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) Überschreiben Sie getFilter () in Ihrem benutzerdefinierten Adapter und filtern Sie die Ergebnisse und benachrichtigen Sie die Listenansicht, dass sich die Datenmenge geändert hat.

  @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) results.values; MyCustomAdapter.this.notifyDataSetChanged(); } @Override protected FilterResults performFiltering(CharSequence constraint) { Log.d(Constants.TAG, "**** PERFORM FILTERING for: " + constraint); List filteredResults = getFilteredResults(constraint); FilterResults results = new FilterResults(); results.values = filteredResults; return results; } }; } 

Hier ein interessantes Beispiel

 public Filter getFilter() { return new Filter() { @Override protected FilterResults performFiltering(CharSequence constraint) { final FilterResults oReturn = new FilterResults(); final ArrayList results = new ArrayList(); 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) results.values; notifyDataSetChanged(); } }; } public void notifyDataSetChanged() { super.notifyDataSetChanged(); notifyChanged = true; } 

Für diejenigen, die die Filterable Schnittstelle nicht benötigen, gibt es eine viel einfachere Lösung. Dies behandelt auch notifyDataSetChanged() korrekt, wenn die anderen Lösungen fehlschlagen. Beachten Sie, dass Sie dem BaseAdapter eine function getArray() BaseAdapter , die nur das Array-Objekt zurückgibt, das an den Konstruktor übergeben wurde.

 public abstract class BaseFilterAdapter extends BaseAdapter { private List original; private String lastFilter; public BaseFilterAdapter(Context context, List array) { super(context, new LinkedList()); 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 getArray() { return original; } @Override public void notifyDataSetChanged() { filter(lastFilter); } } 

Fügen Sie zuString override für Ihre Basisklasse hinzu. Beispielsweise

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

Oben macht Ihre Liste als String-Liste. So können Sie verwenden:

 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) { } });