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();
}
};
}
}
comment pourrais-je « définir les résultats filtrés sur mon adaptateur que le nouvel ensemble de données pour afficher »? – RaKXeR
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
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