0

J'ai une classe class CustomAdapter extends ArrayAdapter<CustomListItem>, où CustomListItem implements Parcelable, et dispose de 3 variables chaîne (String a, b, c;)Filtrage ListView personnalisé avec plusieurs TextViews à l'aide d'un filtre sur un ArrayAdapter <T implémente Parcelable>

Tout fonctionne comme prévu lors du chargement du ListView . Cependant, maintenant je veux utiliser mon SearchView pour afficher seulement les éléments de liste qui contiennent le texte que l'utilisateur entre. Je veux que le filtre de CustomAdapter regarde a, b et c pour ce texte, et affiche n'importe quel élément de liste qui contient ce texte. Donc, par exemple, si l'utilisateur tape "ar", et abc sont "Rome", "Male", "Arnold", quel que soit le contenu dans quelle variable, puisque l'un d'eux a "Ar" (je ne veux pas qu'il soit sensible à la casse) Je veux que cet élément soit affiché sur la liste.

Cette entreprise de filtre semble très confus pour moi en ce moment, et il semble y avoir beaucoup de réponses pour filtres personnalisés à stackoverflow, mais je ne peux pas trouver un qui a le genre de comportement que je décris. Jusqu'à présent, voici ce que j'ai:

public class CustomAdapter extends ArrayAdapter<CustomListItem> { 

    public CustomAdapter(Context context, int textViewResourceId) { 
     super(context, textViewResourceId); 
    } 

    public CustomAdapter(Context context, int resource, List<CustomListItem> items) { 
     super(context, resource, items); 
    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 

     View v = convertView; 

     if (v == null) { 
      LayoutInflater vi; 
      vi = LayoutInflater.from(getContext()); 
      v = vi.inflate(R.layout.row_layout, null); 
     } 

     CustomListItem s = getItem(position); 

     if (s != null) { 
      TextView a = (TextView) v.findViewById(R.id.a); 
      TextView b = (TextView) v.findViewById(R.id.b); 
      TextView c = (TextView) v.findViewById(R.id.c); 

      if (a != null) { 
       a.setText(s.getA()); 
      } 

      if (b != null) { 
       b.setText(s.getB()); 
      } 

      if (c != null) { 
       c.setText(s.getC()); 
      } 
     } 
     return v; 
    } 

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

      @Override 
      protected FilterResults performFiltering(CharSequence constraint) { 
       FilterResults result = new FilterResults(); 

       List<CustomListItem> list = new ArrayList<>(); 
       int max = getCount(); 
       for (int cont = 0; cont < max; cont++) { 
        if (constraint != null) { 
         CustomListItem item = getItem(cont); 
         boolean contains = 
           item.getA().toLowerCase().contains(constraint) || 
           item.getB().toLowerCase().contains(constraint) || 
           item.getC().toLowerCase().contains(constraint); 
         if (contains) { 
          list.add(getItem(cont)); 
         } 
        } else { 
         list.add(getItem(cont)); 
        } 
       } 

       result.values = list; 
       result.count = list.size(); 

       return result; 
      } 

      @Override 
      protected void publishResults(CharSequence constraint, FilterResults results) { 
       if (results.count > 0) { 
        notifyDataSetChanged(); 
       } else { 
        notifyDataSetInvalidated(); 
       } 
      } 
     }; 
    } 
} 

Mais cela ne fonctionne pas, probablement parce que je ne sais pas ce que je fais. Ceci est CustomListItem:

public class CustomListItem implements Parcelable { 
    private String a, b, c; 

    public CustomListItem(String a, String b, String c) { 
     this.a = a; 
     this.b = b; 
     this.c = c; 
    } 

    private CustomListItem(Parcel in) { 
     a = in.readString(); 
     b = in.readString(); 
     c = in.readString(); 
    } 

    @Override 
    public void writeToParcel(Parcel dest, int flags) { 
     dest.writeString(a); 
     dest.writeString(b); 
     dest.writeString(c); 
    } 

    public String getA() { 
     return a; 
    } 

    public String getB() { 
     return b; 
    } 

    public String getC() { 
     return c; 
    } 

    @Override 
    public int describeContents(){ 
     return 0; 
    } 

    public static final Parcelable.Creator<CustomListItem> CREATOR 
      = new Parcelable.Creator<CustomListItem>() { 
     public CustomListItem createFromParcel(Parcel in) { 
      return new CustomListItem(in); 
     } 

     public CustomListItem[] newArray(int size) { 
      return new CustomListItem[size]; 
     } 
    }; 
} 

Et j'ajouter le filtre comme celui-ci, sur ma classe AppCompatActivity:

SearchView searchView = (SearchView) findViewById(R.id.searchView); 
final CustomAdapter adapter = new CustomAdapter(getApplicationContext(), R.layout.row_layout, item_list); //item_list is my list of custom items, defined elsewhere 

searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { 
    @Override 
    public boolean onQueryTextSubmit(String text) { 
     adapter.getFilter().filter(text); 
     return true; 
    } 
    @Override 
    public boolean onQueryTextChange(String text) { 
     adapter.getFilter().filter(text); 
     return true; 
    } 
}); 

Je crois que la seule chose qui cloche avec mon code est la méthode getFilter(), donc ce que je Je cherche comme une réponse est une façon correcte et propre de réaliser ce que je viens de dire. Je serai également heureux avec une explication sur ce que je fais mal, et quelques exemples. Merci pour votre temps!

SOLUTION: En fonction de la réponse de Submersed, j'ai apporté les modifications nécessaires pour que le code fonctionne. Comme prévu, le problème était limité au filtre. Cependant, depuis que je changé d'autres choses dans la CustomAdapter classe pour atteindre ma solution, voici toute la classe fixe:

public class CustomAdapter extends ArrayAdapter<CustomListItem> { 

    private final List<CustomListItem> mList; 

    public CustomAdapter(Context context, int resource, List<CustomListItem> items) { 
     super(context, resource, items); 
     mList = new ArrayList<>(items); 
    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 

     View v = convertView; 

     if (v == null) { 
      LayoutInflater vi; 
      vi = LayoutInflater.from(getContext()); 
      v = vi.inflate(R.layout.row_layout, null); 
     } 

     CustomListItem s = getItem(position); 

     if (s != null) { 
      TextView a = (TextView) v.findViewById(R.id.a); 
      TextView b = (TextView) v.findViewById(R.id.b); 
      TextView c = (TextView) v.findViewById(R.id.c); 

      if (a != null) { 
       a.setText(s.getA()); 
      } 

      if (b != null) { 
       b.setText(s.getB()); 
      } 

      if (c != null) { 
       c.setText(s.getC()); 
      } 
     } 
     return v; 
    } 

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

      @Override 
      protected FilterResults performFiltering(CharSequence charSequence) { 
       FilterResults result = new FilterResults(); 
       String constraint = charSequence.toString().toLowerCase(); 

       if (constraint == null || constraint.isEmpty()) { 
        result.values = mList; 
        result.count = mList.size(); 
       } else { 
        List<CustomListItem> list = new ArrayList<>(); 
        int max = mList.size(); 
        for (int cont = 0; cont < max; cont++) { 
         CustomListItem item = mList.get(cont); 
         boolean contains = 
           item.getA().toLowerCase().contains(constraint) || 
           item.getB().toLowerCase().contains(constraint) || 
           item.getC().toLowerCase().contains(constraint); 
         if (contains) { 
          list.add(mList.get(cont)); 
         } 
        } 
        result.values = list; 
        result.count = list.size(); 
       } 

       return result; 
      } 

      @Override 
      protected void publishResults(CharSequence constraint, FilterResults results) { 
       clear(); 
       addAll((ArrayList<CustomListItem>) results.values); 
       notifyDataSetChanged(); 
      } 
     }; 
    } 
} 

Répondre

2

Dans votre méthode publishResults:

 @Override 
     protected void publishResults(CharSequence constraint, FilterResults results) { 
      if (results.count > 0) { 
       notifyDataSetChanged(); 
      } else { 
       notifyDataSetInvalidated(); 
      } 
     } 

Vous n'êtes pas régler le filtré résultats sur votre adaptateur en tant que nouveau jeu de données à afficher avant d'invalider l'ensemble de données. En outre, vous devriez également conserver une copie de vos valeurs d'origine. Ainsi, si vous videz la requête, vous pouvez conserver et réinitialiser les résultats d'origine.

Modifier pour le code exemple Cadre: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/widget/ArrayAdapter.java#ArrayAdapter.ArrayFilter

+0

comment pourrais-je « définir les résultats filtrés sur mon adaptateur que le nouvel ensemble de données pour afficher »? – RaKXeR

+1

Votre filtre contient déjà une référence à votre adaptateur, vous devez donc appeler clear(), puis ajouterAll(). C'est pourquoi vous devez conserver une copie des valeurs d'origine. Il existe déjà une implémentation par défaut du filtre dans ArrayAdapter, il peut donc être utile de vérifier la source. En éditant pour le lien, vérifiez notre ArrayFilter. – Submersed

+0

Merci pour l'aide, j'ai réussi à le faire maintenant basé sur ce que vous m'avez dit, et mettra à jour ma question et marquer votre réponse comme correcte bientôt. Une dernière question cependant: à quoi servent les méthodes 'notifyDataSetChanged()' et 'notifyDataSetInvalidated()'? ils ne me semblent pas pertinents. – RaKXeR