Filtrado personalizado ArrayAdapter en ListView

Soy un principiante en Android, pero traté de hacer un filtro de vista de lista personalizado y funcionó de alguna manera. El único problema que tengo es que ArrayList que conservé todos los valores (ArrayList “original”) es cada vez más bajo en los elementos en cada filtrado. No puedo explicar esto, pero pensé que podías ayudarme de alguna manera.

De todos modos aquí está el ArrayAdaptor personalizado:

public class PkmnAdapter extends ArrayAdapter { private ArrayList original; private ArrayList fitems; private Filter filter; public PkmnAdapter(Context context, int textViewResourceId, ArrayList items) { super(context, textViewResourceId, items); this.original = items;//new ArrayList(); this.fitems = items;//new ArrayList(); } @Override public void add(Pkmn item){ original.add(item); } @Override public View getView(int position, View convertView, ViewGroup parent) { View v = convertView; if (v == null) { LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); v = vi.inflate(R.layout.row, null); } Pkmn pkmn = original.get(position); if (pkmn != null) { TextView tt = (TextView) v.findViewById(R.id.RlabPName); TextView dex = (TextView)v.findViewById(R.id.RlabDex); ImageView img = (ImageView)v.findViewById(R.id.RimgPkmn); if (tt != null) { tt.setText(pkmn.getName()); } if (dex != null){ dex.setText(CalcDex(pkmn.getId())); } if (img != null){ int resId = getContext().getResources().getIdentifier("dex" + pkmn.getId(), "drawable", "com.compileguy.pokebwteam"); img.setImageResource(resId); } } return v; } @Override public Filter getFilter() { if (filter == null) filter = new PkmnNameFilter(); return filter; } private class PkmnNameFilter extends Filter { @Override protected FilterResults performFiltering(CharSequence constraint) { FilterResults results = new FilterResults(); String prefix = constraint.toString().toLowerCase(); if (prefix == null || prefix.length() == 0) { ArrayList list = new ArrayList(original); results.values = list; results.count = list.size(); } else { final ArrayList list = original; int count = list.size(); final ArrayList nlist = new ArrayList(count); for (int i=0; i<count; i++) { final Pkmn pkmn = list.get(i); final String value = pkmn.getName().toLowerCase(); if (value.startsWith(prefix)) { nlist.add(pkmn); } } results.values = nlist; results.count = nlist.size(); } return results; } @SuppressWarnings("unchecked") @Override protected void publishResults(CharSequence constraint, FilterResults results) { fitems = (ArrayList)results.values; clear(); int count = fitems.size(); for (int i=0; i 0) notifyDataSetChanged(); else notifyDataSetInvalidated(); } } private String CalcDex(int id){ String s = String.valueOf(id); if (s.length() == 1) s = "00"+s; else if (s.length() == 2) s = "0"+s; return '#'+s; } 

}

NOTA: La vista de lista muestra correctamente los elementos pero cuando, por ejemplo, elimino una letra en el cuadro de edición (que desencadena el filtrado) aquí es donde comienzan los problemas.

— EDITAR —

@Janusz: Muchas gracias por tu respuesta. Eso resolvió mi problema.

Aquí está el código fuente que funciona para mí, así que si alguien tiene el mismo problema, podría probar este:

 private ArrayList original; private ArrayList fitems; private Filter filter; public PkmnAdapter(Context context, int textViewResourceId, ArrayList items) { super(context, textViewResourceId, items); this.original = new ArrayList(items); this.fitems = new ArrayList(items); } @Override public View getView(int position, View convertView, ViewGroup parent) { View v = convertView; if (v == null) { LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); v = vi.inflate(R.layout.row, null); } Pkmn pkmn = fitems.get(position); if (pkmn != null) { TextView tt = (TextView) v.findViewById(R.id.RlabPName); TextView dex = (TextView)v.findViewById(R.id.RlabDex); ImageView img = (ImageView)v.findViewById(R.id.RimgPkmn); if (tt != null) { tt.setText(pkmn.getName()); } if (dex != null){ dex.setText(CalcDex(pkmn.getId())); } if (img != null){ int resId = getContext().getResources().getIdentifier("dex" + pkmn.getId(), "drawable", "com.compileguy.pokebwteam"); img.setImageResource(resId); } } return v; } @Override public Filter getFilter() { if (filter == null) filter = new PkmnNameFilter(); return filter; } private class PkmnNameFilter extends Filter { @Override protected FilterResults performFiltering(CharSequence constraint) { FilterResults results = new FilterResults(); String prefix = constraint.toString().toLowerCase(); if (prefix == null || prefix.length() == 0) { ArrayList list = new ArrayList(original); results.values = list; results.count = list.size(); } else { final ArrayList list = new ArrayList(original); final ArrayList nlist = new ArrayList(); int count = list.size(); for (int i=0; i<count; i++) { final Pkmn pkmn = list.get(i); final String value = pkmn.getName().toLowerCase(); if (value.startsWith(prefix)) { nlist.add(pkmn); } } results.values = nlist; results.count = nlist.size(); } return results; } @SuppressWarnings("unchecked") @Override protected void publishResults(CharSequence constraint, FilterResults results) { fitems = (ArrayList)results.values; clear(); int count = fitems.size(); for (int i=0; i<count; i++) { Pkmn pkmn = (Pkmn)fitems.get(i); add(pkmn); } } } } 

Tu problema son estas líneas:

 this.original = items; this.fitems = items; 

Items es la lista que usa para su ListView y ponerlo en dos variables diferentes no hace dos listas diferentes. Solo le está dando a la lista elementos de dos nombres diferentes.

Puedes usar:

 this.fitems = new ArrayList(items); 

eso debería generar una nueva lista y los cambios en esta lista solo cambiarán la lista de elementos.

puede lograr el mismo efecto simplemente creando un método toString() en su clase Pkmn que devuelve el valor que desea filtrar.

La mejor manera que encontré para filtrar ArrayAdapter es crear mi propia clase de filtro:

 private class MyFilter extends Filter 

luego en esa función crea la nueva matriz de objetos para mostrar después del filtro (puedes encontrar una buena implementación en el código fuente de la class ArrayAdapter )

 @Override protected FilterResults performFiltering(CharSequence prefix) 

ahora el truco está en este método

 @Override protected void publishResults(CharSequence constraint, FilterResults results) 

cuando utiliza el adaptador de matriz no puede hacer esto:

 myAdapterData = results.values 

desde entonces desconectas tus datos de los superdatos, debes hacer esto para mantener tu referencia a la matriz de datos súper original:

 data.clear(); data.addAll((List) results.values); 

y luego anular

getFilter ()

en su adaptador, por ejemplo:

 @Override public Filter getFilter() { if (filter == null) { filter = new MyFilter(); } return filter; } 
    Intereting Posts