List Filter Custom Adapter Dont Give Result

List Filter Custom Adapter dont give result

You need to implement Filterable to your Adapter Class and Override getFilter()

Checkout this complete example for Filtering custom Adapter.

UPDATE:

      public class ListFilterActivity extends ListActivity {

private List<String> list = new ArrayList<String>();
List<String> mOriginalValues;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

final MyAdapter adapter = new MyAdapter(this, getModel());
setListAdapter(adapter);

EditText filterEditText = (EditText) findViewById(R.id.filterText);

// Add Text Change Listener to EditText
filterEditText.addTextChangedListener(new TextWatcher() {

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// Call back the Adapter with current character to Filter
adapter.getFilter().filter(s.toString());
}

@Override
public void beforeTextChanged(CharSequence s, int start, int count,int after) {
}

@Override
public void afterTextChanged(Editable s) {
}
});
}

private List<String> getModel() {
list.add("Linux");
list.add("Windows7");
list.add("Suse");
list.add("Eclipse");
list.add("Ubuntu");
list.add("Solaris");
list.add("Android");
list.add("iPhone");
list.add("Windows XP");
return list;
}

// Adapter Class
public class MyAdapter extends BaseAdapter implements Filterable {

List<String> arrayList;
List<String> mOriginalValues; // Original Values
LayoutInflater inflater;

public MyAdapter(Context context, List<String> arrayList) {
this.arrayList = arrayList;
inflater = LayoutInflater.from(context);
}

@Override
public int getCount() {
return arrayList.size();
}

@Override
public Object getItem(int position) {
return arrayList.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

private class ViewHolder {
TextView textView;
}

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

ViewHolder holder = null;

if (convertView == null) {

holder = new ViewHolder();
convertView = inflater.inflate(R.layout.row, null);
holder.textView = (TextView) convertView
.findViewById(R.id.textview);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.textView.setText(arrayList.get(position));
return convertView;
}

@Override
public Filter getFilter() {
Filter filter = new Filter() {

@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint,FilterResults results) {

arrayList = (List<String>) results.values; // has the filtered values
notifyDataSetChanged(); // notifies the data with new filtered values
}

@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults(); // Holds the results of a filtering operation in values
List<String> FilteredArrList = new ArrayList<String>();

if (mOriginalValues == null) {
mOriginalValues = new ArrayList<String>(arrayList); // saves the original data in mOriginalValues
}

/********
*
* If constraint(CharSequence that is received) is null returns the mOriginalValues(Original) values
* else does the Filtering and returns FilteredArrList(Filtered)
*
********/
if (constraint == null || constraint.length() == 0) {

// set the Original result to return
results.count = mOriginalValues.size();
results.values = mOriginalValues;
} else {
constraint = constraint.toString().toLowerCase();
for (int i = 0; i < mOriginalValues.size(); i++) {
String data = mOriginalValues.get(i);
if (data.toLowerCase().contains(constraint.toString())) {
FilteredArrList.add(data);
}
}
// set the Filtered result to return
results.count = FilteredArrList.size();
results.values = FilteredArrList;
}
return results;
}
};
return filter;
}
}
}

Filtering a Custom Adapter on listview is not working properly in android?

Your publishResults() method should look like this:

@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if (results.count == 0){
notifyDataSetInvalidated();
} else {
@SuppressWarnings("unchecked")
ArrayList<Custom> lst = (ArrayList<Custom>)results.values;
ArrayList<Custom> itemsList = new ArrayList<Custom>(lst);

entries = itemsList;
clear();
for (Custom item : entries) {
add(item);
}
}
}

Android: Results of filtering custom adapter are not reflecting in the UI

It's normal that you don't see any UI changes, because you aren't updating the right list of data after the filtering. Your MainMenuAdapter is based on the mainCatDAOList list of data, but in the publishResults method where the adapter's data should be refreshed you do:

arrayList = (ArrayList<MainCategoryDAO>) results.values;
notifyDataSetChanged();

As you can see you're updating the arrayList with the filtered values instead of mainCatDAOList so the adapter doesn't see any changes. So your code should be:

protected void publishResults(CharSequence constraint,
FilterResults results) {
Log.v(TAG+" getFilter", "publishResults called");
mainCatDAOList = (ArrayList<MainCategoryDAO>) results.values;
Log.v(TAG+" getFilter", "publishResults arrayList size "+arrayList.size());
for(int i = 0; i < arrayList.size(); i++)
{
Log.v(TAG+" getFilter filtered name", " "+arrayList.get(i).getCategory_name());
}//for
notifyDataSetChanged();
}

Also you should have a copy of the initial list of data to be used for filtering, otherwise you'll not be able to return to the full set of values.

The clear() in custom listview adapter also updates the list data

public class AutoCompleteAdapter extends ArrayAdapter<String> implements Filterable {

private ArrayList<String> fullList;
private ArrayList<String> mOriginalValues;
private ArrayFilter mFilter;

public AutoCompleteAdapter(Context context, int resource, List<String> objects) {

super(context, resource, objects);
fullList = (ArrayList<String>) objects;
mOriginalValues = new ArrayList<String>(fullList);

}

@Override
public void add(String object) {
super.add(object);
fullList.add(object);
mOriginalValues.add(object);
}

@Override
public void clear() {
super.clear();
fullList.clear();
mOriginalValues.clear();
}

@Override
public int getCount() {
return fullList.size();
}

@Override
public String getItem(int position) {
return fullList.get(position);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView view = (TextView) super.getView(position, convertView, parent);
view.setEllipsize(TextUtils.TruncateAt.START);
return view;
}

@Override
public Filter getFilter() {
if (mFilter == null) {
mFilter = new ArrayFilter();
}
return mFilter;
}


private class ArrayFilter extends Filter {

@Override
protected FilterResults performFiltering(CharSequence prefix) {
FilterResults results = new FilterResults();

if (mOriginalValues == null) {
mOriginalValues = new ArrayList<String>(fullList);
}
ArrayList<String> list = new ArrayList<String>(mOriginalValues);
results.values = list;
results.count = list.size();


return results;
}

@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {

if (results.values != null) {
fullList = (ArrayList<String>) results.values;
} else {
fullList = new ArrayList<String>();
}
if (results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
}
}

Check it out. this adapter works great. Good luck.

Android Custom ArrayAdapter doesn't refresh after filter

From what I have determined, it seems that I needed a custom Filter for my custom ArrayAdapter.
The custom ArrayAdapter has an overridden implementation of Filter, here is the code:

import java.util.ArrayList;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Filter;
import android.widget.TextView;

public class PizzaAdapter extends ArrayAdapter<Pizza>{

private ArrayList<Pizza> original;
private ArrayList<Pizza> fitems;
private Filter filter;


public PizzaAdapter(Context context, int textViewResourceId, ArrayList<Pizza> items) {
super(context, textViewResourceId, items);

this.original = new ArrayList<Pizza>(items);
this.fitems = new ArrayList<Pizza>(items);
this.filter = new PizzaFilter();
}

@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.pizza_list_item, null);
}

Pizza pizza = fitems.get(position);

if(pizza != null){
String subtitleString = new String("[" + pizza.getPizzaType() + "] " + pizza.getPizzaCategory() + ": " + pizza.getPizzaCode());

TextView title = (TextView)v.findViewById(R.id.title);
TextView subtitle = (TextView)v.findViewById(R.id.subtitle);

if(title != null){
title.setText(pizza.getPizzaName());
}
if(subtitle != null){
subtitle.setText(subtitleString);
}
}
return v;
}

@Override
public Filter getFilter(){

if(filter == null){
filter = new PizzaFilter();
}
return filter;
}

private class PizzaFilter extends Filter{
@Override
protected FilterResults performFiltering(CharSequence constraint){
FilterResults results = new FilterResults();
String prefix = constraint.toString().toLowerCase();

if (prefix == null || prefix.length() == 0){
ArrayList<Pizza> list = new ArrayList<Pizza>(original);
results.values = list;
results.count = list.size();
}else{
final ArrayList<Pizza> list = new ArrayList<Pizza>(original);
final ArrayList<Pizza> nlist = new ArrayList<Pizza>();
int count = list.size();

for (int i = 0; i<count; i++){
final Pizza pizza = list.get(i);
final String value = Pizza.getPizzaName().toLowerCase();

if(value.contains(prefix)){
nlist.add(pizza);
}
results.values = nlist;
results.count = nlist.size();
}
}
return results;
}

@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
fitems = (ArrayList<Pizza>)results.values;
notifyDataSetChanged();
clear();
int count = fitems.size();
for(int i = 0; i<count; i++){
add(fitems.get(i));
notifyDataSetInvalidated();
}
}
}
}

It turns out that a custom implmentation of Filter updated the display when you searched. Hopefully this will help some people.

Listview custom filter gives wrong item on-clicked in filtered list

I found problem in method (check comments):

private void Filter(String text) {
for (Employee post : employeeArrayList) {
String filterPattern = text.toLowerCase().trim();
if (post.getnumber().toLowerCase().contains(filterPattern)) {
filterList.add(post);
}
}
//below every time you create new instance of MyAdapter - try comment this line (below) and test it
removeView.setAdapter(new MyAdapter(getApplicationContext(), filterList));
//this is your first instance but you set new adapter for listView
adapter.notifyDataSetChanged();
}

and replace your method with this:

private void Filter(String text) {
for (Employee post : employeeArrayList) {
String filterPattern = text.toLowerCase().trim();
if (post.getnumber().toLowerCase().contains(filterPattern)) {
filterList.add(post);
}
}
adapter.clear()
adapter.addAll(filterList);
}

So you don't create a new instance of the adapter every time, just swap data of the existing adapter

I haven't tested it but it should work fine with OnItemClickListener...

EDITED

Also same problem...

@Override
public void afterTextChanged(Editable s) {
filterList.clear();
if (s.toString().isEmpty()) {
//you set new instance of adapter and notify old, try comment this line (below) and test it
//removeView.setAdapter(new MyAdapter(getApplicationContext(), employeeArrayList));
adapter.notifyDataSetChanged();
} else {
Filter(s.toString());
}
}


Change to this

        @Override
public void afterTextChanged(Editable s) {
if (!s.toString().isEmpty()) {
filterList.clear(); //TODO here is problem, move this to your filter method
Filter(s.toString());
} else {
//Do nothing, if the EditText field is empty the list will remain filled
}
}

There are other ways to solve this and improve but I don't want to confuse you, because android is new experience for you

EDITED

You are using an ArrayAdapter but I thought it is RecyclerView, forget swapData method and try new changes... Sorry

adapter.clear()
adapter.addAll(filterList);

Custom ArrayAdapter is not updating when filtering

The ListView isn't filtered because you set the results of the filtering on subItems which is not used in the adapter class so the call to notifyDataSetChanged will not work as from the adapter's point of view the data is intact. You're correct to use another list to hold the old values, they will be required so you have all the old values around. To solve the problem add the line :

subItems = new ArrayList<CustomListItem>(searchArrayList);

in the adapter's constructor, this is so you have a copy of the full values to use later. Then in the publishResults method use the searchArrayList list, because that is the list that backs the adapter:

searchArrayList =  (ArrayList<CustomListItem>)results.values;
notifyDataSetChanged();

Then in the performFiltering method:

  if (prefix!= null && prefix.toString().length() > 0) {
// use the initial values !!!
for (int index = 0; index < subItems.size(); index++) {
CustomListItem si = subItems.get(index);
final int length = prefix.length();
// if you compare the Strings like you did it will never work as you compare the full item string(you'll have a match only when you write the EXACT word)
// keep in mind that you take in consideration capital letters!
if(si.toString().substring(0, prefixLength).compareTo(prefix.toString()) == 0){
i.add(si);
}
}
results.values = i;
results.count = i.size();
}
else{
// revert to the old values
synchronized (searchArrayList){
results.values = subItems;
results.count = subItems.size();
}
}

I hope it works.

(not 100% sure that R.id.custom_title is the id I should be putting
there.

It doesn't matter as you use your own custom adapter.

Custom Listview Adapter with filter Android

You can use the Filterable interface on your Adapter, have a look at the example below:

public class SearchableAdapter extends BaseAdapter implements Filterable {

private List<String>originalData = null;
private List<String>filteredData = null;
private LayoutInflater mInflater;
private ItemFilter mFilter = new ItemFilter();

public SearchableAdapter(Context context, List<String> data) {
this.filteredData = data ;
this.originalData = data ;
mInflater = LayoutInflater.from(context);
}

public int getCount() {
return filteredData.size();
}

public Object getItem(int position) {
return filteredData.get(position);
}

public long getItemId(int position) {
return position;
}

public View getView(int position, View convertView, ViewGroup parent) {
// A ViewHolder keeps references to children views to avoid unnecessary calls
// to findViewById() on each row.
ViewHolder holder;

// When convertView is not null, we can reuse it directly, there is no need
// to reinflate it. We only inflate a new View when the convertView supplied
// by ListView is null.
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item, null);

// Creates a ViewHolder and store references to the two children views
// we want to bind data to.
holder = new ViewHolder();
holder.text = (TextView) convertView.findViewById(R.id.list_view);

// Bind the data efficiently with the holder.

convertView.setTag(holder);
} else {
// Get the ViewHolder back to get fast access to the TextView
// and the ImageView.
holder = (ViewHolder) convertView.getTag();
}

// If weren't re-ordering this you could rely on what you set last time
holder.text.setText(filteredData.get(position));

return convertView;
}

static class ViewHolder {
TextView text;
}

public Filter getFilter() {
return mFilter;
}

private class ItemFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence constraint) {

String filterString = constraint.toString().toLowerCase();

FilterResults results = new FilterResults();

final List<String> list = originalData;

int count = list.size();
final ArrayList<String> nlist = new ArrayList<String>(count);

String filterableString ;

for (int i = 0; i < count; i++) {
filterableString = list.get(i);
if (filterableString.toLowerCase().contains(filterString)) {
nlist.add(filterableString);
}
}

results.values = nlist;
results.count = nlist.size();

return results;
}

@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
filteredData = (ArrayList<String>) results.values;
notifyDataSetChanged();
}

}
}

In your Activity or Fragment where of Adapter is instantiated :

editTxt.addTextChangedListener(new TextWatcher() {

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
System.out.println("Text ["+s+"]");

mSearchableAdapter.getFilter().filter(s.toString());
}

@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {

}

@Override
public void afterTextChanged(Editable s) {
}
});

Here are the links for the original source and another example

CustomArrayAdapter doesn't refresh after filter text has been removed

The way you are using nightsOut as the source list for your ArrayAdapter and also the source list for the filter is what is causing the problem.

In the publishResults() method you have a call to clear() which removes all elements from the nightsOut list inside ArrayAdapter since that is the list it references. You then readd only the filtered data.

Then the next time call performFiltering() you are using nightsOut as the source list again which only includes the filtered items.

What you want to do instead is keep a reference to your original items. You don't really need items the way it is currently used so I would rename that to originalItems and do the following:

public CustomArrayAdapter(Activity context, ArrayList<NightOut> nightsOut) {
super(context, R.layout.list_item, nightsOut);
this.context = context;
this.nightsOut = nightsOut;
originalItems = new ArrayList<>(nightsOut); // create a copy of nightsOut.
}

And then the filter

private class NightFilter extends Filter {

@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
ArrayList<NightOut> tempList = (ArrayList<NightOut>) results.values;
clear();
addAll(tempList);
}

@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults result = new FilterResults();
if (constraint == null || constraint.length() == 0) {
result.values = originalItems;
result.count = originalItems.size();
} else {
final ArrayList<NightOut> nlist = new ArrayList<NightOut>();
String lowerConstraint = constraint.toString().toLowerCase();

// loop through originalItems which always contains all items
for(NightOut nightOut : originalItems) {
final String value = nightOut.getAddress().toLowerCase();
if (value.contains(lowerConstraint)) {
nlist.add(nightOut);
}
}

result.values = nlist;
result.count = nlist.size();
}

return result;
}
}


Related Topics



Leave a reply



Submit