Filtrado personalizado ArrayAdapter en ListView

Soy un begginer en Android, pero he intentado hacer un filtro de listview personalizado y yo funcionó de alguna manera. El único problema que tengo es que el ArrayList que guardé todos los valores ("original" ArrayList), está consiguiendo más bajo y más bajo en artículos en cada filtrado. No puedo explicar esto pero pensé que puedes ayudarme de alguna manera.

De todos modos aquí es el Custom ArrayAdaptor:

public class PkmnAdapter extends ArrayAdapter<Pkmn> { private ArrayList<Pkmn> original; private ArrayList<Pkmn> fitems; private Filter filter; public PkmnAdapter(Context context, int textViewResourceId, ArrayList<Pkmn> items) { super(context, textViewResourceId, items); this.original = items;//new ArrayList<Pkmn>(); this.fitems = items;//new ArrayList<Pkmn>(); } @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<Pkmn> list = new ArrayList<Pkmn>(original); results.values = list; results.count = list.size(); } else { final ArrayList<Pkmn> list = original; int count = list.size(); final ArrayList<Pkmn> nlist = new ArrayList<Pkmn>(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<Pkmn>)results.values; clear(); int count = fitems.size(); for (int i=0; i<count; i++) { Pkmn pkmn = (Pkmn)fitems.get(i); add(pkmn); } if (fitems.size() > 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: El listview muestra correctamente los elementos pero cuando para exaple elimino una letra en el editbox (que desencadena el filtrado) aquí es donde empiezan los problemas.

— EDITAR —

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

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

 private ArrayList<Pkmn> original; private ArrayList<Pkmn> fitems; private Filter filter; public PkmnAdapter(Context context, int textViewResourceId, ArrayList<Pkmn> items) { super(context, textViewResourceId, items); this.original = new ArrayList<Pkmn>(items); this.fitems = new ArrayList<Pkmn>(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<Pkmn> list = new ArrayList<Pkmn>(original); results.values = list; results.count = list.size(); } else { final ArrayList<Pkmn> list = new ArrayList<Pkmn>(original); final ArrayList<Pkmn> nlist = new ArrayList<Pkmn>(); 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<Pkmn>)results.values; clear(); int count = fitems.size(); for (int i=0; i<count; i++) { Pkmn pkmn = (Pkmn)fitems.get(i); add(pkmn); } } } } 

Su problema son estas líneas:

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

Elementos es la lista que utiliza para su ListView y ponerla en dos variables diferentes no hace dos listas diferentes fuera de ella. Usted está dando solamente a los artículos de la lista dos nombres diferentes.

Puedes usar:

 this.fitems = new ArrayList(items); 

Que debe generar una nueva Lista y los cambios en esta lista solo cambiarán la lista de fitems.

Puede lograr el mismo efecto 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 

Entonces en esa función crear la nueva matriz de objetos para mostrar después del filtro (se puede encontrar una buena aplicació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 se desconectan los datos de los superdatos, debe hacer esto para mantener su referencia a la matriz de datos super original:

 data.clear(); data.addAll((List<YourType>) results.values); 

Y luego anular

GetFilter ()

En su adaptador, por ejemplo:

 @Override public Filter getFilter() { if (filter == null) { filter = new MyFilter(); } return filter; } 
  • ¿Cómo interceptar una intención de Google Maps en Android?
  • ¿Cómo puedo usar filtro para emma cuando construyo una prueba de Android con hormigas?
  • ListAdapter Filtro que no sea el uso de cadenas?
  • Android: Intento de filtro para un patrón Uri específico
  • No hay resultados con ArrayAdapter Filter
  • Índice de matriz de Android ListView fuera de límites después del filtro
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.