I have a ListView with a custom adapter in a fragment. Everything works fine but now I'm trying to implement a way for filtering the list when typing in an EditText (I've tried a SearchView but it did not work either). Each row has two EditTexts and a ImageView.
In OnCreateView
:
lst=(ListView)rootView.findViewById(R.id.lst);
lst.setTextFilterEnabled(true);
mainAd = new mArrayAdapter(getActivity(),R.layout.row,downList); //it's more complicated than this but normally the ListView is populated correctly
lst.setAdapter(mainAd);
lst.setTextFilterEnabled(true);
edit = (EditText) rootView.findViewById(R.id.txtexample);
edit.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
mainAd.getFilter().filter(charSequence.toString());
}
@Override
public void afterTextChanged(Editable editable) {
}
});
return rootView;
The mArrayAdapter
:
private class mArrayAdapter extends ArrayAdapter<Exhibition> implements Filterable{
Context context;
int layoutResourceId;
ArrayList<Exhibition> list;
ValueFilter valueFilter;
ArrayList<Exhibition> filterList;
mArrayAdapter(Context context, int layoutResourceId, ArrayList<Exhibition> data){
super(context, layoutResourceId, data);
this.context=context;
this.layoutResourceId=layoutResourceId;
this.list=data;
this.filterList =data;
}
@Override
@NonNull
public View getView(int position, View convertView, @NonNull ViewGroup parent) {
View row;
Exhibition ex;
if(convertView==null){
row= getActivity().getLayoutInflater().inflate(R.layout.row,parent,false);
}
else row = convertView;
TextView ttl = (TextView)row.findViewById(R.id.title);
TextView descr = (TextView)row.findViewById(R.id.descr);
ImageView header = (ImageView)row.findViewById(R.id.hd);
ex = downList.get(position);
ttl.setText(ex.name);
descr.setText(ex.description);
byte[] decoded = Base64.decode(ex.image,Base64.DEFAULT);
Bitmap decodedBitmap = BitmapFactory.decodeByteArray(decoded,0,decoded.length);
header.setImageBitmap(decodedBitmap);
return row;
}
@Override
public Filter getFilter() {
if (valueFilter == null) {
valueFilter = new ValueFilter();
}
return valueFilter;
}
private class ValueFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
String filtString = constraint.toString().toLowerCase();
FilterResults results = new FilterResults();
if(constraint == null || constraint.length() == 0){
results.values = filterList;
results.count = filterList.size();
}
else {
List<Exhibition> nExhList = new ArrayList<>();
for(Exhibition e : list){
if (e.getName().toLowerCase().startsWith(constraint.toString().toLowerCase())){
nExhList.add(e);
}
}
results.values= nExhList;
results.count=nExhList.size();
}
return results;
}
@Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
if(results.count==0){
notifyDataSetInvalidated();
}
else{
list = (ArrayList<Exhibition>)results.values;
notifyDataSetChanged();
}
}
}
}
I don't know why it's not working. Thanks in advance.
I solved my problem.
I add the changes I did for make it works but, if you have the same problem, note that at THIS link there is an example I made to filter correctly a ListView with an EditText and a SearchView.
For first, in edit.addTextChangedListener
:
edit.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (i2 < i1) {
mainAd.resetData(); //if I delete characters I would like to show the original list
}
mainAd.getFilter().filter(charSequence.toString());
}
@Override
public void afterTextChanged(Editable editable) {
}
});
For second, in the mArrayAdapter
I checked the right variables (for example, I was calling the original ArrayList in getView()
) and I add three methods that are needed:
@Override
public int getCount(){
return list.size();
}
@Override
public Exhibition getItem (int pos){
return list.get(pos);
}
void resetData() {
list = originalList;
}
(I changed the name of filterList
in originalList
)
The ValueFilter
is the following:
private class ValueFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if(constraint == null || constraint.length() == 0){
results.values = originalList;
results.count = originalList.size();
}
else {
List<Exhibition> nExhList = new ArrayList<>();
for(Exhibition e : list){
if (e.getName().toUpperCase().startsWith(constraint.toString().toUpperCase())){
nExhList.add(e);
}
}
results.values= nExhList;
results.count=nExhList.size();
}
return results;
}
@Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
if(results.count==0){
notifyDataSetInvalidated();
}
else{
list = (ArrayList<Exhibition>)results.values;
notifyDataSetChanged();
}
}
}