I have a problem with my custom filter. I make it, and it works well. When I debug code, it filtrates array well, but I have a problem in void publishResults(). I don't know what is a problem, anyone helps?
public class KatalogAdapter extends ArrayAdapter<Katalog> implements Filterable {
List<Katalog> object;
int num = 0;
public KatalogAdapter(#NonNull Context context, #LayoutRes int resource, #NonNull List<Katalog> objects) {
super(context, resource, objects);
object = objects;
}
public void setObject(List<Katalog> kat){
this.object = kat;
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
View v = convertView;
if(v==null) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.katalozi_item, null);
}
Katalog katalog = object.get(position);
ImageView katalogImage = (ImageView) v.findViewById(R.id.katalogImage);
TextView katalogProizvodjac = (TextView) v.findViewById(R.id.katalogProizvodjac);
TextView katalogVaziDo = (TextView) v.findViewById(R.id.katalogVaziDo);
TextView idKataloga = (TextView) v.findViewById(R.id.idKataloga);
String src = katalog.getImageSRC();
Picasso.with(getContext()).load(src).into(katalogImage);
/*Glide.with(getContext()).load(src).thumbnail(Glide.with(getContext()).load(R.drawable.loading_icon))
.fitCenter()
.crossFade().into(katalogImage); */
// katalogImage.setImageBitmap(bitmap);
katalogProizvodjac.setText(katalog.getKatalogProizvodjac());
String doe = katalog.getKatalogVaziDo();
char lastChar = doe.charAt(doe.length() - 1);
if(lastChar=='1'){
katalogVaziDo.setText("Važi još "+ doe +" dan");
}
if(doe.equals("0")){
katalogVaziDo.setText("Važi još danas");
}
if(lastChar!='1' && !doe.equals("0")){
katalogVaziDo.setText("Važi još "+katalog.getKatalogVaziDo() + " dana");
}
// katalogVaziDo.setText("Važi do: "+katalog.getKatalogVaziDo());
idKataloga.setText(String.valueOf(katalog.getIdKataloga()));
return v;
}
#Override
public Filter getFilter() {
return new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults filterResults = new FilterResults();
ArrayList<Katalog> tempList=new ArrayList<Katalog>();
//constraint is the result from text you want to filter against.
//objects is your data set you will filter from
if(constraint != null && object!=null) {
int length=object.size();
int i=0;
while(i<length){
Katalog item=object.get(i);
if(item.getKatalogProizvodjac().toLowerCase(Locale.getDefault()).contains(constraint.toString().toLowerCase())){
tempList.add(item);
}
i++;
}
//following two lines is very important
//as publish result can only take FilterResults objects
filterResults.values = tempList;
filterResults.count = tempList.size();
}
return filterResults;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
// object = (ArrayList<Katalog>) results.values;
setObject((List<Katalog>) results.values);
num = results.count;
notifyDataSetChanged();
}
};
}
}
I was looking for an answer, and I found that in that function I need to put in array my data. I did it, but still not work.
i am provide recyler view adapter with filter for contact details and you can change code your need according.
public class InviteContactAdapter extends RecyclerView.Adapter<InviteContactAdapter.ItemViewHolder> implements Filterable {
private List<UserContact> mContactList = new ArrayList<>();
private List<UserContact> mContectFilter = new ArrayList<>();
private Context mContext;
private CustomFilter mFilter;
public List<String> mEmailList = new ArrayList<>();
public InviteContactAdapter(Context context, List<UserContact> mContactList) {
mContext = context;
this.mContactList = mContactList;
this.mContectFilter = mContactList;
mFilter = new CustomFilter();
}
public onItemClickListener onItemClickListener;
public void setOnItemClickListener(InviteContactAdapter.onItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
#Override
public ItemViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.invite_contact_row_layout, viewGroup, false);
return new ItemViewHolder(view);
}
public interface onItemClickListener {
void onClick(UserContact contact);
}
#Override
public Filter getFilter() {
return mFilter;
}
#Override
public void onBindViewHolder(final ItemViewHolder itemViewHolder, int i) {
final UserContact contact = mContectFilter.get(i);
itemViewHolder.mTvUserNane.setText(contact.getUserName().trim());
itemViewHolder.mTvUserEmail.setText(contact.getUserEmail().trim());
if (contact.isSelect())
itemViewHolder.mIvSelect.setImageResource(R.drawable.check_contect);
else
itemViewHolder.mIvSelect.setImageResource(R.drawable.un_check_contact);
itemViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (contact.isSelect()) {
contact.setSelect(false);
itemViewHolder.mIvSelect.setImageResource(R.drawable.un_check_contact);
} else {
contact.setSelect(true);
itemViewHolder.mIvSelect.setImageResource(R.drawable.check_contect);
}
}
});
}
#Override
public int getItemCount() {
return mContectFilter.size();
}
public class ItemViewHolder extends RecyclerView.ViewHolder {
private TextView mTvUserNane, mTvUserEmail;
private ImageView mIvSelect;
public ItemViewHolder(View itemView) {
super(itemView);
mTvUserEmail = itemView.findViewById(R.id.icrlTvUserEmail);
mTvUserNane = itemView.findViewById(R.id.icrlTvUserName);
mIvSelect = itemView.findViewById(R.id.icrlIvSelect);
}
}
public List<String> getEmail() {
mEmailList.clear();
for (UserContact contact : mContectFilter) {
if (contact.isSelect()) {
mEmailList.add(contact.getUserEmail());
}
}
return mEmailList;
}
/**
* this class for filter data.
*/
class CustomFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence charSequence) {
FilterResults results = new FilterResults();
if (charSequence != null && charSequence.length() > 0) {
ArrayList<UserContact> filters = new ArrayList<>();
charSequence = charSequence.toString().toUpperCase();
for (int i = 0; i < mContactList.size(); i++) {
if (mContactList.get(i).getUserName().toUpperCase().contains(charSequence) || mContactList.get(i).getUserEmail().toUpperCase().contains(charSequence)) {
UserContact contact = new UserContact();
contact.setUserName(mContactList.get(i).getUserName());
contact.setUserEmail(mContactList.get(i).getUserEmail());
filters.add(contact);
}
}
results.count = filters.size();
results.values = filters;
} else {
results.count = mContactList.size();
results.values = mContactList;
}
return results;
}
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
mContectFilter = (ArrayList<UserContact>) filterResults.values;
notifyDataSetChanged();
}
}
}
and call into activity in edittext box for filter record like below ..
filter the data
Note: make sure your adapter object not null
/**
* this method filter data.
*/
private void sortData(View root) {
mEtSearchData = (EditText) root.findViewById(R.id.icffEtSearch);
mEtSearchData.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (inviteContactAdapter != null) {
inviteContactAdapter.getFilter().filter(s);
}
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
My problem was that in some line I hade gridView.setAdapter(null).
However, I had one more problem, in gridView I had 5 elements, after filtering, I had one item filled with real data and 4 more empty items.. So, I changed getView function..
If someone need it, here it is:
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
View v = convertView;
if(v==null) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.katalozi_item, null);
}
if(objectfilt.size()>position){
Katalog katalog = objectfilt.get(position);
ImageView katalogImage = (ImageView) v.findViewById(R.id.katalogImage);
TextView katalogProizvodjac = (TextView) v.findViewById(R.id.katalogProizvodjac);
TextView katalogVaziDo = (TextView) v.findViewById(R.id.katalogVaziDo);
TextView idKataloga = (TextView) v.findViewById(R.id.idKataloga);
String src = katalog.getImageSRC();
Picasso.with(getContext()).load(src).into(katalogImage);
/*Glide.with(getContext()).load(src).thumbnail(Glide.with(getContext()).load(R.drawable.loading_icon))
.fitCenter()
.crossFade().into(katalogImage); */
// katalogImage.setImageBitmap(bitmap);
katalogProizvodjac.setText(katalog.getKatalogProizvodjac());
String doe = katalog.getKatalogVaziDo();
char lastChar = doe.charAt(doe.length() - 1);
if(lastChar=='1'){
katalogVaziDo.setText("Važi još "+ doe +" dan");
}
if(doe.equals("0")){
katalogVaziDo.setText("Važi još danas");
}
if(lastChar!='1' && !doe.equals("0")){
katalogVaziDo.setText("Važi još "+katalog.getKatalogVaziDo() + " dana");
}
// katalogVaziDo.setText("Važi do: "+katalog.getKatalogVaziDo());
idKataloga.setText(String.valueOf(katalog.getIdKataloga()));
return v;
}
else {
v.setVisibility(View.GONE);
return v;
}
So, elements from ListArray objectfilt are added, and when int position become bigger than number of ListView elements, then just hide that views.
Related
I wrote a custom ArrayAdapter with a custom Filter for my AutoCompleteTextView. It shows everything correctly, but when I filter the suggestions and click on an item, it takes the string of the item that was at this position in the suggestion list when ALL items were shown. I made screenshot to clarify what I mean:
And this is my code:
public class AutoCompleteCountryAdapter extends ArrayAdapter<CountryItem> {
private List<CountryItem> countryList;
private List<CountryItem> filteredCountryList = new ArrayList<>();
public AutoCompleteCountryAdapter(#NonNull Context context, #NonNull List<CountryItem> countryList) {
super(context, 0, countryList);
this.countryList = countryList;
}
#Override
public int getCount() {
return filteredCountryList.size();
}
#NonNull
#Override
public Filter getFilter() {
return countryFilter;
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
CountryItem countryItem = filteredCountryList.get(position);
LayoutInflater inflater = LayoutInflater.from(getContext());
if (convertView == null) {
convertView = inflater.inflate(
R.layout.country_autocomplete_row, parent, false
);
}
TextView textViewName = convertView.findViewById(R.id.text_view_name);
ImageView imageViewFlag = convertView.findViewById(R.id.image_view_flag);
textViewName.setText(countryItem.getCountryName());
imageViewFlag.setImageResource(countryItem.getFlagImage());
return convertView;
}
private Filter countryFilter = new Filter() {
private List<CountryItem> suggestions = new ArrayList<>();
#Override
protected FilterResults performFiltering(CharSequence constraint) {
suggestions.clear();
FilterResults results = new FilterResults();
if (constraint == null || constraint.length() == 0) {
suggestions.addAll(countryList);
} else {
String filterPattern = constraint.toString().toLowerCase().trim();
for (CountryItem item : countryList) {
if (item.getCountryName().toLowerCase().contains(filterPattern)) {
suggestions.add(item);
}
}
}
results.values = suggestions;
results.count = suggestions.size();
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
filteredCountryList.clear();
filteredCountryList.addAll((List) results.values);
notifyDataSetChanged();
}
#Override
public CharSequence convertResultToString(Object resultValue) {
return ((CountryItem) resultValue).getCountryName();
}
};
}
I solved it.
I have no idea why this did not appear in any tutorial I found (including the Materialdoc one), but you also have to override getItem in the adapter, to pick it's item from the filtered List, not the original List:
public CountryItem getItem(int position) {
return filteredCountryList.get(position);
}
i provide one adapter class that used recylerview adapter for user contact adapter that filter user contact. you can make changes your requirement according into code..
public class InviteContactAdapter extends RecyclerView.Adapter<InviteContactAdapter.ItemViewHolder> implements Filterable {
private List<UserContact> mContactList = new ArrayList<>();
private List<UserContact> mContectFilter = new ArrayList<>();
private Context mContext;
private CustomFilter mFilter;
public List<String> mEmailList = new ArrayList<>();
public InviteContactAdapter(Context context, List<UserContact> mContactList) {
mContext = context;
this.mContactList = mContactList;
this.mContectFilter = mContactList;
mFilter = new CustomFilter();
}
public onItemClickListener onItemClickListener;
public void setOnItemClickListener(InviteContactAdapter.onItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
#Override
public ItemViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.invite_contact_row_layout, viewGroup, false);
return new ItemViewHolder(view);
}
public interface onItemClickListener {
void onClick(UserContact contact);
}
#Override
public Filter getFilter() {
return mFilter;
}
#Override
public void onBindViewHolder(final ItemViewHolder itemViewHolder, int i) {
final UserContact contact = mContectFilter.get(i);
itemViewHolder.mTvUserNane.setText(contact.getUserName().trim());
itemViewHolder.mTvUserEmail.setText(contact.getUserEmail().trim());
if (contact.isSelect())
itemViewHolder.mIvSelect.setImageResource(R.drawable.check_contect);
else
itemViewHolder.mIvSelect.setImageResource(R.drawable.un_check_contact);
itemViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (contact.isSelect()) {
contact.setSelect(false);
itemViewHolder.mIvSelect.setImageResource(R.drawable.un_check_contact);
} else {
contact.setSelect(true);
itemViewHolder.mIvSelect.setImageResource(R.drawable.check_contect);
}
}
});
}
#Override
public int getItemCount() {
return mContectFilter.size();
}
public class ItemViewHolder extends RecyclerView.ViewHolder {
private TextView mTvUserNane, mTvUserEmail;
private ImageView mIvSelect;
public ItemViewHolder(View itemView) {
super(itemView);
mTvUserEmail = itemView.findViewById(R.id.icrlTvUserEmail);
mTvUserNane = itemView.findViewById(R.id.icrlTvUserName);
mIvSelect = itemView.findViewById(R.id.icrlIvSelect);
}
}
public List<String> getEmail() {
mEmailList.clear();
for (UserContact contact : mContectFilter) {
if (contact.isSelect()) {
mEmailList.add(contact.getUserEmail());
}
}
return mEmailList;
}
/**
* this class for filter data.
*/
class CustomFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence charSequence) {
FilterResults results = new FilterResults();
if (charSequence != null && charSequence.length() > 0) {
ArrayList<UserContact> filters = new ArrayList<>();
charSequence = charSequence.toString().toUpperCase();
for (int i = 0; i < mContactList.size(); i++) {
if (mContactList.get(i).getUserName().toUpperCase().contains(charSequence) || mContactList.get(i).getUserEmail().toUpperCase().contains(charSequence)) {
UserContact contact = new UserContact();
contact.setUserName(mContactList.get(i).getUserName());
contact.setUserEmail(mContactList.get(i).getUserEmail());
filters.add(contact);
}
}
results.count = filters.size();
results.values = filters;
} else {
results.count = mContactList.size();
results.values = mContactList;
}
return results;
}
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
mContectFilter = (ArrayList<UserContact>) filterResults.values;
notifyDataSetChanged();
}
}
}
ArrayList<YourModel> arrayList = new ArrayList<>();
arrayList.addAll(yourList);
AutoCompleteAdapter autoCompleteAdapter = new AutoCompleteAdapter(context, arrayList);
autoCompleteTextView.setAdapter(brandAdapter);
autoCompleteTextView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
YourModel model = (YourModel) autoCompleteAdapter.getItem(position);
autoCompleteTextView.setText(model.getText());
autoCompleteTextView.setSelection(model.getText().length());
}
});
AutoCompleteAdapter.java
public class AutoCompleteAdapter extends BaseAdapter implements Filterable {
private Context context;
private ArrayList<YourModel> originalList;
private ArrayList<YourModel> suggestions = new ArrayList<>();
private Filter filter = new CustomFilter();
public AutoCompleteAdapter(Context context, ArrayList<YourModel> originalList) {
this.context = context;
this.originalList = originalList;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
try {
if (convertView == null) {
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_filter, parent, false);
}
YourModel model = suggestions.get(position);
AppCompatTextView tvTitle = convertView.findViewById(R.id.tvTitle);
tvTitle.setText(model.getText());
} catch (NullPointerException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return convertView;
}
#Override
public Object getItem(int position) {
return suggestions.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public int getCount() {
return suggestions.size();
}
#Override
public Filter getFilter() {
return filter;
}
private class CustomFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
suggestions.clear();
if (originalList != null && constraint != null) {
for (int i = 0; i < originalList.size(); i++) {
if (originalList.get(i).getText().toLowerCase().contains(constraint.toString().toLowerCase().trim())) {
suggestions.add(originalList.get(i));
}
}
}
FilterResults results = new FilterResults();
results.values = suggestions;
results.count = suggestions.size();
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if (results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
}
}
I have a search text input field and a recycle view with adapter items loaded and when i enter data into search field recycle view adapter has to get filtered according to the search input and then display it. But I am not able to filter the content its just displaying the old times after i entered data into search field also.Kindly help me with my error and tell me how to resolve it
SearchInput code:
txtDynamicSearch.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int
count) {
//DynamicSearchActivity.this.arrayAdapter.getFilter().filter(s);
DynamicSearchActivity.this.customListAdapter.getFilter().filter(s);
}
#Override
public void afterTextChanged(Editable s) {
}
});
Filter code:
public class CustomListAdapter extends
RecyclerView.Adapter<CustomListAdapter.MyViewHolder>
implements Filterable{
private ArrayList<samples> allsamplesList;
private ArrayList<samples> filteredsamplesList;
private Activity context;
private LayoutInflater inflater;
private sampleFilter filter;
Integer imageId = R.drawable.icon;
RecyclerView recyclerView;
public static class MyViewHolder extends RecyclerView.ViewHolder {
TextView textViewName;
TextView textViewLanguage;
//ImageView imageViewIcon;*/
public MyViewHolder(View itemView) {
super(itemView);
this.textViewName = (TextView)
itemView.findViewById(R.id.textViewName);
this.textViewLanguage = (TextView)
itemView.findViewById(R.id.textViewLanguage);
/*this.imageViewIcon = (ImageView)
itemView.findViewById(R.id.imageView);
*/}
}
public CustomListAdapter(Activity context, ArrayList<samples> list) {
//super(context, R.layout.item, list);
this.context = context;
this.allsamplesList = new ArrayList<samples>();
allsamplesList.addAll(list);
this.filteredsamplesList = new ArrayList<samples>();
filteredsamplesList.addAll(allsamplesList);
inflater = context.getLayoutInflater();
getFilter();
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.cards_layout, viewGroup, false);
//view.setOnClickListener(DynamicSearchActivity);
MyViewHolder myViewHolder = new MyViewHolder(view);
return myViewHolder;
}
#Override
public void onBindViewHolder(MyViewHolder myViewHolder, int i) {
TextView textViewName = myViewHolder.textViewName;
TextView textViewLanguage = myViewHolder.textViewLanguage;
textViewName.setText(allsamplesList.get(i).getsample_name());
textViewLanguage.setText(allsamplesList.get(i).getsample_language());
}
#Override
public int getItemCount() {
return allsamplesList.size();
}
#Override
public Filter getFilter() {
if (filter == null) {
filter = new sampleFilter(this);
}
return filter;
}
private class sampleFilter extends Filter {
private CustomListAdapter adapter;
private sampleFilter(CustomListAdapter adapter) {
super();
this.adapter = adapter;
}
#Override
protected FilterResults performFiltering(CharSequence constraint) {
constraint = constraint.toString().toUpperCase();
FilterResults results = new FilterResults();
if (constraint != null && constraint.toString().length() > 0) {
ArrayList<samples> filteredItems = new ArrayList<samples>();
for (int i=0; i < allsamplesList.size(); i++ ) {
samples samples = allsamplesList.get(i);
if (samples.getsample_name().contains(constraint)) {
filteredItems.add(samples);
notifyItemRangeChanged(i,allsamplesList.size());
}
}
results.count = filteredItems.size();
results.values = filteredItems;
}
else {
synchronized (this) {
results.count = allsamplesList.size();
results.values = allsamplesList;
}
}
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults
results) {
filteredsamplesList = (ArrayList<samples>) results.values;
Collections.sort(filteredsamplesList, new Comparator<samples>() {
#Override
public int compare(samples lhs, samples rhs) {
return lhs.getsample_name().compareTo(rhs.getsample_name());
}
});
notifyDataSetChanged();
adapter.notifyDataSetChanged();
adapter.filteredsamplesList.clear();
adapter.filteredsamplesList.addAll((ArrayList<samples>)
results.values);
adapter.filteredsamplesList = (filteredsamplesList);
int n = results.count;
for (int i=0; i < filteredsamplesList.size(); i++) {
adapter.filteredsamplesList.add(filteredsamplesList.get(i));
adapter.notifyItemInserted(i);
adapter.notifyDataSetChanged();
//notifyItemRangeChanged(0,n);
}
adapter.notifyDataSetChanged();
notifyDataSetInvalidated();
adapter.notifyDataSetChanged();
notifyDataSetChanged();
Log.e("values", constraint.toString());
//Log.e("values",
String.valueOf((filteredsamplesList.get(0)).sample_name));
}
}
}
I have implement search for my application. For that I have used an adapter as well. I have loaded 30 items to the search screen. When I pressed letter z to search, then letter z belongs to 4 items out of 30 items in the list.
According to the below shown code it identifies the number 4 and shows the first 4 items out of the 30 items. When I debug inside getFilter(), it shows the filtered items correctly(I have provided a screen shot).
My problem is how can I load the filtered items. Bit confused here.
search.java
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.search_results_activity);
new SearchMenuAsyncTask(getApplicationContext(), this).execute();
listtv = (LinearLayout) findViewById(R.id.product_lv);
lv = (ListView) findViewById(R.id.list_view);
inputSearch = (EditText) findViewById(R.id.inputSearch);
lv.setTextFilterEnabled(true);
inputSearch.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
System.out.println("Text ["+s+"]");
adapter.getFilter().filter(s.toString());
TextView headerTV = (TextView) findViewById(R.id.search_header);
headerTV.setText("SEARCH RESULTS");
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
#Override
public void onTaskCompleted(JSONArray responseJson) {
try {
final List<String> menudescriptions = new ArrayList<String>();
for (int i = 0; i < responseJson.length(); ++i) {
final JSONObject object = responseJson.getJSONObject(i);
if ((object.getString("MainCategoryID")).equals("1")
&& (object.getString("SubCategoryID")).equals("1")
&& (object.getString("Visible")).equals("true")) {
Log.i("descriptionsTop ", object.getString("Description"));
descriptions.add(object.getString("Description"));
Log.i("MenuDescription ",
object.getString("MenuDescription"));
menudescriptions
.add(object.getString("MenuDescription"));
}
adapter = new CustomListSearch(
getApplicationContext(), descriptions,
menudescriptions);
lv.setAdapter(adapter);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
CustomListSearch.java
public class CustomListSearch extends BaseAdapter implements Filterable {
private Context context;
List<String> descriptions;
private List<String>filteredDescriptions;
private final List<String> menudescriptions;
private ItemFilter mFilter = new ItemFilter();
private LayoutInflater mInflater;
ArrayAdapter<String> adapter;
public CustomListSearch(Context c, List<String> data,
List<String> menudescriptions) {
this.context = c;
this.filteredDescriptions = data ;
this.descriptions = data;
this.menudescriptions = menudescriptions;
mInflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return filteredDescriptions.size();
}
#Override
public Object getItem(int position) {
return filteredDescriptions.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
private class ViewHolder {
private TextView tvMenudescriptions;
private TextView tvDescriptions;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = LayoutInflater.from(context).inflate(
R.layout.search_list_item, parent, false);
holder.tvDescriptions = (TextView) convertView
.findViewById(R.id.product_name);
holder.tvMenudescriptions = (TextView) convertView
.findViewById(R.id.product_description);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.tvDescriptions.setText(descriptions.get(position));
holder.tvMenudescriptions.setText(menudescriptions.get(position));
LinearLayout itemlist = (LinearLayout) convertView
.findViewById(R.id.product_lv);
itemlist.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(context, "Still under constructions...",
Toast.LENGTH_LONG).show();
}
});
return convertView;
}
#Override
public Filter getFilter() {
// TODO Auto-generated method stub
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 = descriptions;
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) {
filteredDescriptions = (ArrayList<String>) results.values;
notifyDataSetChanged();
}
}
}
Screen shot
To filter adapter that contains list of custom object
Create a Object:
public class TvObject {
String name;
String description;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
After:
public class CustomListSearch extends BaseAdapter implements Filterable {
private Context context;
private ItemFilter mFilter = new ItemFilter();
private LayoutInflater mInflater;
private List<TvObject> mListTvObject = new ArrayList<>();
private List<TvObject> mListTvObjectFiltered = new ArrayList<>();
public CustomListSearch(Context c, List<TvObject> mListTvObject) {
this.context = c;
mInflater = LayoutInflater.from(context);
this.mListTvObject = mListTvObject;
this.mListTvObjectFiltered = mListTvObject;
}
#Override
public int getCount() {
return mListTvObjectFiltered.size();
}
#Override
public Object getItem(int position) {
return mListTvObjectFiltered.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
private class ViewHolder {
private TextView tvMenudescriptions;
private TextView tvDescriptions;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = mInflater.inflate(R.layout.search_list_item, parent, false);
holder.tvDescriptions = (TextView) convertView.findViewById(R.id.product_name);
holder.tvMenudescriptions = (TextView) convertView.findViewById(R.id.product_description);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.tvDescriptions.setText(mListTvObjectFiltered.get(position).getName());
holder.tvMenudescriptions.setText(mListTvObjectFiltered.get(position).getDescription());
LinearLayout itemlist = (LinearLayout) convertView.findViewById(R.id.product_lv);
itemlist.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(context, "Still under constructions...",Toast.LENGTH_LONG).show();
}
});
return convertView;
}
#Override
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();
int count = mListTvObject.size();
final ArrayList<TvObject> mListResult = new ArrayList<>();
String name;
for (int i = 0; i < count; i++) {
TvObject mTvObject = mListTvObject.get(i);
name = mTvObject.getName();
if (name.toLowerCase().contains(filterString)) {
mListResult.add(mTvObject);
}
}
results.values = mListResult;
results.count = mListResult.size();
return results;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, Filter.FilterResults results) {
mListTvObjectFiltered = (ArrayList<TvObject>) results.values;
notifyDataSetChanged();
}
}
}
Edited:
In your Activity do something like this!
try {
final List<TvObject > mListObjects = new ArrayList<>();
for (int i = 0; i < responseJson.length(); ++i) {
final JSONObject object = responseJson.getJSONObject(i);
if ((object.getString("MainCategoryID")).equals("1")
&& (object.getString("SubCategoryID")).equals("1")
&& (object.getString("Visible")).equals("true")) {
Log.i("descriptionsTop ", object.getString("Description"));
Log.i("MenuDescription ", object.getString("MenuDescription"));
TvObject mTvObject = new TvObject();
mTvObject.setName(object.getString("Description"));
mTvObject.setDescription(object.getString("MenuDescription"));
mListObjects.add(mTvObject);
}
adapter = new CustomListSearch( getApplicationContext(), mListObjects);
lv.setAdapter(adapter);
}
} catch (JSONException e) {
e.printStackTrace();
}
I am using a custom adapter with a search filter in a fragment, however the results don't get filtered on a search, I debugged and stepped through my code and find that it is saying that the args.listenere = null!. What does this mean and how do I correct it? My code is below:
---------Custom Adapter -------
public class SalesPartAdapter extends BaseAdapter implements Filterable {
private ArrayList<SalesPartItem> listData;
private ArrayList<SalesPartItem> filteredData;
private SalesPartFilter filter;
private Context _context;
private LayoutInflater layoutInflater;
public SalesPartAdapter(Context context, ArrayList<SalesPartItem> listData) {
this.listData = listData;
layoutInflater = LayoutInflater.from(context);
_context = context;
}
#Override
public int getCount() {
return listData.size();
}
#Override
public Object getItem(int position) {
return listData.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
//set background colour
if (convertView == null) {
//set up holder
convertView = layoutInflater.inflate(R.layout.salespart_item, null);
holder = new ViewHolder();
holder.salesPartCodeView = (TextView) convertView.findViewById(R.id.salesPartCode);
holder.salesPartDescView = (TextView) convertView.findViewById(R.id.salesPartDescription);
holder.salesPartColourBar= (ImageView) convertView.findViewById(R.id.colourBar);
convertView.setTag(holder);
} else {
//use existing holder
holder = (ViewHolder) convertView.getTag();
}
SalesPartItem salespartView = (SalesPartItem) listData.get(position);
holder.salesPartCodeView.setText(salespartView.SalesPartCode);
holder.salesPartDescView.setText(salespartView.SalesPartDescription);
holder.salesPartColourBar.setBackgroundColor(Color.parseColor(salespartView.Colour));//String.valueOf(salespartView.Colour);
return convertView;
}
/********* holder Class to contain previously inflated xml file elements *********/
static class ViewHolder {
TextView salesPartCodeView;
TextView salesPartDescView;
ImageView salesPartColourBar;
}
public Filter getFilter() {
if (filter == null){
filter = new SalesPartFilter();
}
return filter;
}
ArrayList<SalesPartItem> filteredItems;
ArrayList<Integer>countFilteredItems;
private class SalesPartFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
constraint = constraint.toString().toLowerCase();
FilterResults result = new FilterResults();
if(constraint != null && constraint.toString().length() > 0)
{
filteredItems = new ArrayList<SalesPartItem>();
// countFilteredItems = new ArrayList<Integer>();
for(int i = 0, l = listData.size(); i < l; i++)
{
SalesPartItem salesPartItem = listData.get(i);
if(salesPartItem.SalesPartDescription.toString().toLowerCase().contains(constraint))
filteredItems.add(salesPartItem);
// countFilteredItems.add(i);
}
result.count = filteredItems.size();
result.values = filteredItems;
}
else
{
synchronized(this)
{
result.values = listData;
result.count = listData.size();
}
}
return result;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
// notifyDataSetChanged();
if (results.count > 0) {
listData =(ArrayList<SalesPartItem>)results.values;
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
}
}
----------------Fragment code that deals with the list view -------------------
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//USE SAMPLE ID TO GET SALES PARTS LIST FROM DATABASE
addSalesParts.setEnabled(false);
//ListViewModel (SalesPartId,salesPartName,NotUsed)
final int numberOfAddedSalesParts = 3;
SalesPartItem sp;
// fill with some dummy data for now.
for (long i = 1; i < numberOfAddedSalesParts; i++) {
sp = new SalesPartItem();
sp.SalesPartItemId = i;
sp.SalesPartCode = "LEU" + i;
if(i!=2){
sp.SalesPartDescription = "Sales Part " + i;
}
else{
sp.SalesPartDescription = "TSalZes Part " + i;
}
sp.Colour = "#cccccc";
salesPartListViewItems.add(sp);
}
// Start of Search filtering
mListView = (ListView) getActivity().findViewById(R.id.salespartsList);
//click on item - edit order
mListView.setTextFilterEnabled(true);
//display the list via our custom adapter
mListView.setAdapter(new SalesPartAdapter(getActivity(), salesPartListViewItems);
EditText searchField = (EditText) getActivity().findViewById(R.id.typeFindSalesPart);
searchField.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
//TODO Search Lists from Database and filter accordingly
SalesPartAdapter SA = new SalesPartAdapter(getActivity(), salesPartListViewItems);
SA.getFilter().filter(s.toString());
Toast.makeText(getActivity(), s, Toast.LENGTH_SHORT).show();
// salesPartListViewItems.contains(s);
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
});
I have now resolved this, the issue was that I was creating a new instance of the adapter in the text watcher. Once I set it to use the adapter that created the original list then it worked fine
Nothing happening even i am entering exact "key" name in EditText whereas it has to be show only that record in a list.
Filtering is not working, this is how my JSON looks like:
{
"data": [
{
"id": "1",
"name": "Era Locksmith",
"key": "EraLoc2015"
},
{
"id": "2",
"name": "Mac Garage Door",
"key": "MacGdr2015"
}
]
}
I am extending ArrayAdapter<....> and implementing Filterable
CompanyListAdapter.java:
public class CompanyListAdapter extends ArrayAdapter<Company> implements Filterable {
private Context context;
ArrayList<Company> products;
SharedPreference sharedPreference;
private ArrayList<Company> filteredCompanies;
private CompanyFilter mFilter = new CompanyFilter();
public CompanyListAdapter(Context context, ArrayList<Company> products) {
super(context, R.layout.company_list_item, products);
this.context = context;
this.products = products;
sharedPreference = new SharedPreference();
}
#Override
public Filter getFilter() {
return mFilter;
}
private class ViewHolder {
TextView productNameTxt;
TextView productKeyTxt;
ImageView favoriteImg;
}
#Override
public int getCount() {
return products.size();
}
#Override
public Company getItem(int position) {
return products.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.company_list_item, null);
holder = new ViewHolder();
holder.productNameTxt = (TextView) convertView
.findViewById(R.id.txt_pdt_name);
holder.productKeyTxt = (TextView) convertView
.findViewById(R.id.txt_pdt_price);
holder.favoriteImg = (ImageView) convertView
.findViewById(R.id.imgbtn_favorite);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Company product = (Company) getItem(position);
holder.productNameTxt.setText(product.getName());
holder.productKeyTxt.setText(product.getPrice() + "");
/*If a product exists in shared preferences then set heart_red drawable
* and set a tag*/
if (checkFavoriteItem(product)) {
holder.favoriteImg.setImageResource(R.drawable.heart_red);
holder.favoriteImg.setTag("red");
} else {
holder.favoriteImg.setImageResource(R.drawable.heart_grey);
holder.favoriteImg.setTag("grey");
}
return convertView;
}
/*Checks whether a particular product exists in SharedPreferences*/
public boolean checkFavoriteItem(Company checkProduct) {
boolean check = false;
List<Company> favorites = sharedPreference.getFavorites(context);
if (favorites != null) {
for (Company product : favorites) {
if (product.equals(checkProduct)) {
check = true;
break;
}
}
}
return check;
}
#Override
public void add(Company product) {
super.add(product);
products.add(product);
notifyDataSetChanged();
}
#Override
public void remove(Company product) {
super.remove(product);
products.remove(product);
notifyDataSetChanged();
}
private class CompanyFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
String filterString = constraint.toString().toLowerCase();
FilterResults results = new FilterResults();
final List<Company> list = products;
int count = list.size();
final ArrayList<Company> nlist = new ArrayList<Company>(count);
Company filterableCompany;
for (int i = 0; i < count; i++) {
filterableCompany = list.get(i);
if (filterableCompany.getKey().toLowerCase().contains(filterString)) {
nlist.add(filterableCompany);
}
}
results.values = nlist;
results.count = nlist.size();
return results;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
filteredCompanies = (ArrayList<Company>) results.values;
notifyDataSetChanged();
}
}
}
Using EditText to accept "key"
CompanyListActivity.java:
EditText filterList = (EditText) view.findViewById(R.id.editKey);
filterList.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// TODO Auto-generated method stub
productListAdapter.getFilter().filter(s.toString());
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
#Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}
});
I am using code provided by #Leigh
Why not use implement Filterable?
Try something like this:
Make your adapter class look like this:
public class CompanyListAdapter extends ArrayAdapter<Company> implements Filterable {
private List<Company> companies;
private List<Company> filteredCompanies;
private CompanyFilter mFilter = new CompanyFilter();
private Context context;
SharedPreference sharedPreference;
public CompanyListAdapter(Context context, ArrayList<Company> products) {
super(context, R.layout.company_list_item, products);
this.context = context;
this.products = products;
this.filteredCompanies = products;
sharedPreference = new SharedPreference();
}
#Override
public int getCount() {
return filteredCompanies == null 0 : filteredCompanies.size();
}
#Override
public Company getItem(int position) {
return filteredCompanies.get(position);
}
#Override
public Filter getFilter() {
return mFilter;
}
}
Next go ahead and create a CompanyFilter:
private class CompanyFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
String filterString = constraint.toString().toLowerCase();
FilterResults results = new FilterResults();
final List<Company> list = companies;
int count = list.size();
final ArrayList<Company> nlist = new ArrayList<Company>(count);
Company filterableCompany;
for (int i = 0; i < count; i++) {
filterableCompany = list.get(i);
if (filterableCompany.getName().toLowerCase().contains(filterString)) {
nlist.add(filterableCompany);
}
}
results.values = nlist;
results.count = nlist.size();
return results;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
filteredCompanies = (ArrayList<Company>) results.values;
notifyDataSetChanged();
}
}
This way you get to apply your filter to any number of fields. Note I am using the getName() of the company class to apply the filter in my example.
EDIT:
TO use this in an Activity / Fragment for searching you can add a TextWatcher to your EditText and apply the filter onTextChanged. Something like this:
txtSearch.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
adapter.getFilter().filter(s.toString());
}
});
you need to make your adapter implement Filterable like this:
class CustomAdapter extends BaseAdapter implements Filterable {
#Override
public Filter getFilter() { ...}
try to look at this answer:
List View Filter Android