I use a recyclerview which I modify thanks to Diffutils. Unfortunately, when I filter my recyclerview and delete items, the index of the deleted items does not match that of my list.
For instance, if I have 3 items: [a, ab,abc] with the index (0,1,2) and I filter with the word "ab", the newly displayed items are [ab, abc] with the index (0,1) so when I try to delete items from the recyclerView, index are wrong.
This is a part of my recycler code
public class NoteListAdapter extends RecyclerView.Adapter<NoteListAdapter.NoteListViewHolder> implements Filterable {
private List<Note> noteList;
private List<Note> noteListFull;
private NoteEventListener listener;
private CustomFilter filter;
public NoteListAdapter(List<Note> noteList, NoteEventListener noteEventListener) {
this.noteList = noteList;
this.noteListFull = noteList;
this.listener = noteEventListener;
}
public void updateList(List<Note> newList) {
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffUtils(this.noteList, newList));
noteList.clear();
noteList.addAll(newList);
diffResult.dispatchUpdatesTo(this);
}
public void insertList(List<Integer> index, List<Note> newList) {
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffUtils(this.noteList, newList));
for (int i =0; i < newList.size(); i++)
noteList.add(index.get(i), newList.get(i));
diffResult.dispatchUpdatesTo(this);
}
#Override
public void onBindViewHolder(#NonNull final NoteListViewHolder holder, int position) {
final Note note = noteList.get(position);
if (note != null) {
holder.itemView.setOnClickListener(v -> listener.onNoteClick(position, note));
holder.itemView.setOnLongClickListener(v -> {
listener.onNoteLongClick(position, note);
return true;
});
}
}
#Override
public Filter getFilter() {
if(filter == null)
filter = new CustomFilter();
return filter;
}
class CustomFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults filterResults = new FilterResults();
if(constraint == null || constraint.length() == 0) {
filterResults.values = noteListFull;
filterResults.count = noteListFull.size();
}
else {
String pattern = constraint.toString().toLowerCase();
List<Note> filters = new ArrayList<>();
for(Note item: noteListFull) {
if (item.getTitle().toLowerCase().contains(pattern)) {
Note n = new Note(item.getTitle(), item.getContent());
filters.add(n);
}
}
filterResults.values = filters;
filterResults.count = filters.size();
}
return filterResults;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
noteList = (List) results.values;
notifyDataSetChanged();
}
}
}
And this is my code when I delete an item:
private void delete_note() {
// Position of all selected items ready to be deleted (but with wrong index)
List<Integer> selectedItems = noteListAdapter.getSelectedItems();
List<Note> temp = new ArrayList<>(notes);
List<Note> deletedItems = selectedItems.stream().map(notes::get).collect(Collectors.toList());
temp.removeAll(deletedItems);
noteListAdapter.updateList(temp);
}
Related
I created an app that has an autoCompleteTextView in order to allow the user to perform search queries.
Once they start typing, a dropdown appears and offers the results.
Now, I would like to make the first item to be fixed and unscrollable which will say something like: can't find? add manually.
How can I make the first item in the suggested dropdown list to be fixed and appear always?
My code for the adapter is:
public class AutoCompleteImageAdapter extends ArrayAdapter<String> implements Filterable {
private ArrayList<String> fullList;
private ArrayList<String> mOriginalValues;
private ArrayFilter mFilter;
private Boolean noResults;
private TextView tv_name;
private ImageView im_cover;
private List<String> url, id;
private StorageReference storageRef;
private FirebaseFirestore db;
public AutoCompleteImageAdapter(Context context, int resource, int textViewResourceId, List<String> objects, List<String> url, List<String> id, Boolean noResult) {
super( context, resource, textViewResourceId, objects );
fullList = (ArrayList<String>) objects;
mOriginalValues = new ArrayList<String>( fullList );
noResults = noResult;
this.url = url;
this.id = id;
}
#Override
public int getCount() {
if (fullList.size() > 40) {
return 40;
} else {
return fullList.size();
}
}
#Override
public String getItem(int position) {
return fullList.get( position );
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
db = FirebaseFirestore.getInstance();
storageRef = FirebaseStorage.getInstance().getReference();
View row = convertView;
String id = this.id.get( position );
LayoutInflater inflater = LayoutInflater.from( getContext() );
if (row == null) {
row = inflater.inflate( R.layout.item_auto_add, parent, false );
}
tv_name = (TextView) row.findViewById( R.id.item_drop );
tv_name.setText( fullList.get( position ) );
im_cover = row.findViewById( R.id.iv_itemCover );
String Url = url.get( position );
if (id.length() > AppConstants.UPLOADED_item_LENGTH) {
storageRef.child( "/itemCovers/" + Url + "/" + Url + ".jpg" ).getDownloadUrl().addOnSuccessListener( new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
Picasso.with( parent.getContext() ).load( uri ).resize( 110, 160 ).into( im_cover );
}
} ).addOnFailureListener( new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
Log.d( "ERROR", exception + "" );
}
} );
} else {
Picasso.with( parent.getContext() ).load( Uri.parse( Url ) ).error( R.drawable.ic_nocover ).resize( 110, 160 ).into( im_cover );
}
return row;
}
#Override
public Filter getFilter() {
if (mFilter == null) {
mFilter = new ArrayFilter();
}
return mFilter;
}
private class ArrayFilter extends Filter {
private Object lock;
#Override
protected FilterResults performFiltering(CharSequence prefix) {
FilterResults results = new FilterResults();
if (mOriginalValues == null) {
synchronized (lock) {
mOriginalValues = new ArrayList<String>( fullList );
}
}
if (prefix == null || prefix.length() == 0) {
synchronized (lock) {
ArrayList<String> list = new ArrayList<String>( mOriginalValues );
results.values = list;
results.count = list.size();
}
} else {
final String prefixString = prefix.toString().toLowerCase();
ArrayList<String> values = mOriginalValues;
int count = values.size();
ArrayList<String> newValues = new ArrayList<String>( count );
for (int i = 0; i < count; i++) {
String item = values.get( i );
if (item.toLowerCase().contains( prefixString )) {
newValues.add( item );
}
}
results.values = newValues;
results.count = newValues.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();
}
}
}
public void clear() {
if (fullList != null) {
fullList.clear();
notifyDataSetChanged();
}
}
}
Thank you
add it as the first item to your List objects before you pass it to the adapter and then populate the list with data you wanna show as search result so that element 0 is always "can't find? add manually". This way it is always there and the other items change.
and then in the item click listener you can check for the item text and act accordingly if it matches "can't find? add manually".
I think the code below solves your requirement to some level. Do try and comment.
<AutoCompleteTextView
android:layout_below="#+id/edit_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/project"
android:id="#+id/edit_project"
android:completionThreshold="0"
android:completionHint="#string/message"
android:inputType="text"
/>
This code gives a hint at the bottom of the list to the user.
My question is similar to this Implementing Search Filter in Adapter Class which parses a json array (without using pojo)
but I would like to try to struggle the problem differently. I have a list of elements that must be filtered based on a condition and once this condition is verified, I want to retrieve the elements that verify it from the json array. In this example, I filtered the elements based on their name, and in the setContentValue () I would set the code and the hex string taking only those elements that have that name, otherwise during filtering the name has a different index from the code and the hex strings. How could I do that?
Fragment
public class ColorViewFragment extends Fragment {
private RecyclerView recyclerView;
private JSONArray json;
private ColorListAdapter adapter;
private EditText editColor;
#Nullable #Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.color_list, container, false);
this.recyclerView = view.findViewById(R.id.recyclerView);
/*
try {
this.recyclerView.setAdapter(new ColorListAdapter(this.json));
} catch (JSONException e) {
e.printStackTrace();
}
*/
try {
adapter = new ColorListAdapter(json);
} catch (JSONException e) {
e.printStackTrace();
}
recyclerView.setAdapter(adapter);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getActivity());
this.recyclerView.setLayoutManager(layoutManager);
//
editColor = view.findViewById(R.id.editText);
editColor.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) {
ColorViewFragment.this.adapter.getFilter().filter(s);
}
#Override
public void afterTextChanged(Editable s) {
}
});
return view;
}
public void setJSON(JSONArray newJson){
this.json = newJson;
}
Adapter
public class ColorListAdapter extends RecyclerView.Adapter implements Filterable {
private JSONArray colorList;
private List<String> colorListFiltered = new ArrayList<String>();
public ColorListAdapter(JSONArray json) throws JSONException {
super();
if (json != null) {
this.colorList = json;
for (int i=0;i<json.length();i++){
//colorListFiltered.add((colorList.getString(i)));
colorListFiltered.add(json.getJSONObject(i).getString("Name"));
}
}
}
#Override
public Filter getFilter() {
return new colorFilter();
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.fragment_color_view, viewGroup, false);
return new ColorListHolder(view);
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder viewHolder, int i) {
try {
((ColorListHolder) viewHolder).setContentValue(i);
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
public int getItemCount() {
return this.colorListFiltered.size();
}
private class ColorListHolder extends RecyclerView.ViewHolder {
private TextView colorCodeText;
private TextView colorNameText;
private CardView imageView;
public ColorListHolder(#NonNull View itemView) {
super(itemView);
this.colorCodeText = itemView.findViewById(R.id.colorCode_text);
this.colorNameText = itemView.findViewById(R.id.colorName_text);
this.imageView = itemView.findViewById(R.id.colorView);
}
public void setContentValue(int index) throws JSONException {
this.colorNameText.setText(colorListFiltered.get(index));
//this.colorNameText.setText(((JSONObject) colorList.get(index)).getString("Name"));
this.colorCodeText.setText(((JSONObject) colorList.get(index)).getString("ColorCode"));
this.imageView.setCardBackgroundColor(Color.parseColor(((JSONObject) colorList.get(index)).getString("HexString")));
}
}
public class colorFilter extends Filter{
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults Result = new FilterResults();
// if constraint is empty return the original names
if(constraint.length() == 0 ) {
ArrayList<String> arrColorList = new ArrayList<>();
for (int i = 0; i < colorList.length(); i++) {
try {
arrColorList.add(colorList.getJSONObject(i).getString("Name"));
} catch (JSONException e) {
e.printStackTrace();
}
}
Result.values = arrColorList;
Result.count = arrColorList.size();
return Result;
}
/*if(constraint.length() == 0 ){
Result.values = colorList;
Result.count = colorList.length();
return Result;*/
else {
List<String> Filtered_Names = new ArrayList<String>();
String filterString = constraint.toString().toLowerCase();
String filterableString = "";
for (int i = 0; i < colorList.length(); i++) {
try {
filterableString = (colorList.getJSONObject(i)).getString("Name");
} catch (JSONException e) {
e.printStackTrace();
}
if (filterableString.toLowerCase().contains(filterString)) {
Filtered_Names.add(filterableString);
}
}
Result.values = Filtered_Names;
Result.count = Filtered_Names.size();
return Result;
}
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
colorListFiltered = (ArrayList<String>) results.values;
notifyDataSetChanged();
}
}
I am near solution, list loads and get filtered, but when I delete word, I get a ClassCastException: String cannot be cast to JSONObject (in setContentValue).
public class ColorListAdapter extends RecyclerView.Adapter implements Filterable {
private List<JSONObject> colorList = new ArrayList<JSONObject>();
private List<JSONObject> colorListFiltered = new ArrayList<JSONObject>();
public ColorListAdapter(JSONArray json) throws JSONException {
super();
if (json != null) {
for(int i=0; i<json.length(); i++) {
JSONObject jsonObj = json.getJSONObject(i);
colorList.add(jsonObj);
colorListFiltered = colorList;
}
}
}
#Override
public Filter getFilter() {
return new colorFilter();
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.fragment_color_view, viewGroup, false);
return new ColorListHolder(view);
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder viewHolder, int i) {
try {
((ColorListHolder) viewHolder).setContentValue(i);
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
public int getItemCount() {
return this.colorListFiltered.size();
}
private class ColorListHolder extends RecyclerView.ViewHolder {
private TextView colorNameText;
private TextView colorCodeText;
private CardView imageView;
public ColorListHolder(#NonNull View itemView) {
super(itemView);
this.colorCodeText = itemView.findViewById(R.id.colorCode_text);
this.colorNameText = itemView.findViewById(R.id.colorName_text);
this.imageView = itemView.findViewById(R.id.colorView);
}
public void setContentValue(final int index) throws JSONException {
this.colorNameText.setText(colorListFiltered.get(index).getString("Name"));
this.colorCodeText.setText(colorListFiltered.get(index).getString("ColorCode"));
this.imageView.setCardBackgroundColor(Color.parseColor(colorListFiltered.get(index).getString("HexString")));
}
}
//filtro su Name
public class colorFilter extends Filter{
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults Result = new FilterResults();
// if constraint is empty return the original names
if(constraint.length() == 0 ) {
ArrayList<String> arrNameList = new ArrayList<>();
for (int i = 0; i < colorList.size(); i++) {
try {
arrNameList.add(colorList.get(i).getString("Name"));
} catch (JSONException e) {
e.printStackTrace();
}
}
Result.values = arrNameList;
Result.count = arrNameList.size();
return Result;
}
else {
List<JSONObject> Filtered_Names = new ArrayList<JSONObject>();
String filterString = constraint.toString().toLowerCase();
String filterableString = "";
for (int i = 0; i < colorList.size(); i++) {
try {
filterableString = (colorList.get(i)).getString("Name");
} catch (JSONException e) {
e.printStackTrace();
}
if (filterableString.toLowerCase().contains(filterString)) {
Filtered_Names.add(colorList.get(i));
}
}
Result.values = Filtered_Names;
Result.count = Filtered_Names.size();
return Result;
}
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
colorListFiltered = (ArrayList<JSONObject>) results.values;
notifyDataSetChanged();
}
}
}
You use colorListFiltered for names but you use colorList for hex codes in setContentValue. First two lists are same but when you filter colorListFiltered they are getting different.
Change this,
private JSONArray colorList;
private List<String> colorListFiltered = new ArrayList<String>();
to
private List<JSONObject> colorList = new ArrayList<JSONObject>();
private List<JSONObject> colorListFiltered = new ArrayList<JSONObject>();
and your performFiltering
List<JSONObject> Filtered_Names = new ArrayList<JSONObject>();
String filterString = constraint.toString().toLowerCase();
String filterableString = "";
for (int i = 0; i < colorList.size(); i++) {
try {
filterableString = (colorList.get(i)).getString("Name");
} catch (JSONException e) {
e.printStackTrace();
}
if (filterableString.toLowerCase().contains(filterString)) {
Filtered_Names.add(colorList.get(i));
}
}
setContentValue:
public void setContentValue(int index) throws JSONException {
this.colorNameText.setText(colorListFiltered.get(index).getString("Name"));
this.colorCodeText.setText(colorListFiltered.get(index).getString("ColorCode"));
this.imageView.setCardBackgroundColor(Color.parseColor(colorListFiltered.get(index).getString("HexString"));
}
I'm creating a project, that uses a webservice to fetch the number of departments and there names and creates dynamic checkboxs.
Then I'm using filterable to filter the adapter , by checking from sharedpreferences if the checkbox is checked if not checked I try to hide it from the adapter
(TicketsActivity):
for (int i=0;i<filterList.size();i++) {
if (!getFromSP(filterList.get(i) + i)) {
mAdapter.getFilter("Department").filter(filterList.get(i).toLowerCase());
}
}
and afther that
if (recyclerView.getAdapter() == null) {
mAdapter.notifyItemRangeInserted(0,ticketList.size()-1);
recyclerView.setAdapter(mAdapter);
} else {
recyclerView.getAdapter().notifyItemRangeInserted(0,ticketList.size()-1);
}
And in my custom Adapter
(TicketsAdapter):
public Filter getFilter(final String type) {
return new Filter() {
#Override
protected FilterResults performFiltering(CharSequence charSequence) {
String charString = charSequence.toString();
if (charString.isEmpty()) {
ticketListFiltered = ticketList;
} else if (type.equals("Search")) {
List<Ticket> filteredList = new ArrayList<>();
for (Ticket row : ticketList) {
if (row.getTitle().toLowerCase().contains(charSequence) || row.getDate().toLowerCase().contains(charSequence) || row.getPriority().toLowerCase().contains(charSequence)) {
filteredList.add(row);
}
}
ticketListFiltered = filteredList;
} else {
List<Ticket> filteredList;
filteredList = ticketList;
for (Ticket row : ticketList) {
if (row.getDepartment().toLowerCase().contains(charSequence)) {
filteredList.remove(row);
}
}
ticketListFiltered = filteredList;
}
FilterResults filterResults = new FilterResults();
filterResults.values =ticketListFiltered;
return filterResults;
}
#Override
public int getItemCount() {
return ticketListFiltered == null ? 0 : ticketListFiltered.size();
}
However this throws an Exception on 'int java.util.List.size()' getItemCount, if i change the filteredList.remove(row) to filteredList.add(row) it will work find,but i need to remove from the adapter rows with "unchecked" department.But for some reason instead of filtering the adapter, its actualy deleting rows direcly of the adapter. I can't find what i'm doing wrong.
Btw this works fine with SearchView
Currently i can search only one string word. example, I need to search for multiple words i type "nougat,donut" and they show me these two? What i need to put in code for this to work?
DataAdapter.java
public class DataAdapter extends RecyclerView.Adapter<DataAdapter.ViewHolder> implements Filterable {
private ArrayList<AndroidVersion> mArrayList;
private ArrayList<AndroidVersion> mFilteredList;
public DataAdapter(ArrayList<AndroidVersion> arrayList) {
mArrayList = arrayList;
mFilteredList = arrayList;
}
#Override
public DataAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.card_row, viewGroup, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(DataAdapter.ViewHolder viewHolder, int i) {
viewHolder.tv_name.setText(mFilteredList.get(i).getName());
viewHolder.tv_version.setText(mFilteredList.get(i).getVer());
viewHolder.tv_api_level.setText(mFilteredList.get(i).getApi());
}
#Override
public int getItemCount() {
return mFilteredList.size();
}
#Override
public Filter getFilter() {
return new Filter() {
#Override
protected FilterResults performFiltering(CharSequence charSequence) {
String charString = charSequence.toString();
if (charString.isEmpty()) {
mFilteredList = mArrayList;
} else {
ArrayList<AndroidVersion> filteredList = new ArrayList<>();
for (AndroidVersion androidVersion : mArrayList) {
if (androidVersion.getApi().toLowerCase().contains(charString) || androidVersion.getName().toLowerCase().contains(charString) || androidVersion.getVer().toLowerCase().contains(charString)) {
filteredList.add(androidVersion);
}
}
mFilteredList = filteredList;
}
FilterResults filterResults = new FilterResults();
filterResults.values = mFilteredList;
return filterResults;
}
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
mFilteredList = (ArrayList<AndroidVersion>) filterResults.values;
notifyDataSetChanged();
}
};
}
public class ViewHolder extends RecyclerView.ViewHolder{
private TextView tv_name,tv_version,tv_api_level;
public ViewHolder(View view) {
super(view);
tv_name = (TextView)view.findViewById(R.id.tv_name);
tv_version = (TextView)view.findViewById(R.id.tv_version);
tv_api_level = (TextView)view.findViewById(R.id.tv_api_level);
}
}
json recycler view
this is search but only for one word
you can try this
if (charString.contains(",")) {
String searchChar[] = charString.split(",");
for (int i = 0; i < searchChar.length; i++) {
if (androidVersion.getApi().toLowerCase().contains(searchChar[i]) || androidVersion
.getName()
.toLowerCase().contains(searchChar[i]) || androidVersion.getVer().toLowerCase()
.contains(searchChar[i])) {
filteredList.add(androidVersion);
}
}
} else {
if (androidVersion.getApi().toLowerCase().contains(charString) || androidVersion.getName()
.toLowerCase().contains(charString) || androidVersion.getVer().toLowerCase()
.contains(charString)) {
filteredList.add(androidVersion);
}
}
replace the code :
if (androidVersion.getApi().toLowerCase().contains(charString) ||
androidVersion.getName().toLowerCase().contains(charString) ||
androidVersion.getVer().toLowerCase().contains(charString)) {
filteredList.add(androidVersion);
}
You need to add some pre-processing to determine if there are multiple values
#Override
protected FilterResults performFiltering(CharSequence charSequence) {
String splitter = ",";
final String[] multipleValues = charSequence.toString().split(splitter);
//your null check
List<AndroidVersions> filteredList = new ArrayList()
for (String value : multipleValues) {
filteredList.addAll(internalFilter(mArrayList, value));
}
//the rest of your code
}
private List<AndroidVersions> internalFilter(ArrayList<AndroidVersions> listToFilter, String value) {
List<AndroidVersions> filteredList = new ArrayList()
for (AndroidVersion androidVersion : listToFilter) {
if (androidVersion.getApi().toLowerCase().contains(value)
|| androidVersion.getName().toLowerCase().contains(value)
|| androidVersion.getVer().toLowerCase().contains(value)) {
filteredList.add(androidVersion);
}
}
return filteredList;
}
This code will also work perfectly fine with only 1 value
i have implemneted search functionality for custom adapter but stil is not working, i have posted my code if anything wrong correct me.
java code
#Override
public Filter getFilter() {
/**
* A filter object which will filter message key
* */
return filter;
}
Filter filter = new Filter() {
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
mEventUtil = (List<Event>) results.values;
notifyDataSetChanged();
}
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if (mOriginalValues == null) {
mOriginalValues = new ArrayList<Event>(mEventUtil); // mOriginalValues
}
// if (mListItem == null) {
// mListItem = new ArrayList<String>();
// for (Event message : mOriginalValues) {
// mListItem.add(message.getEvent_Title());
// }
// }
/**
*
* 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) {
/*
* CONTRACT FOR IMPLEMENTING FILTER : set the Original
* values to result which will be returned for publishing
*/
results.count = mOriginalValues.size();
results.values = mOriginalValues;
} else {
/* Do the filtering */
constraint = constraint.toString().toLowerCase();
List<Event> FilteredArrList = new ArrayList<Event>(mOriginalValues.size());
for (int i = 0; i < mOriginalValues.size(); i++) {
Event event = mOriginalValues.get(i);
if (event.getEvent_Title().toLowerCase().contains(constraint.toString())) {
FilteredArrList.add(event);
}else{
}
}
// set the Filtered result to return
results.count = FilteredArrList.size();
results.values = FilteredArrList;
}
return results;
}
};
This is my most usual implementation:
#Override
public Filter getFilter() {
if (ownfilter == null)
ownfilter = new CustomFilter();
return ownfilter;
}
Basically, ownfilter is an instance of CustomFilter class, which is an extension of the Filter class. In that Filter extension, you have to override the following methods:
protected FilterResults performFiltering(CharSequence): There you define how to perform the filtering over the CharSequence passed to the method. You have to return a FilterResults object, for which you'll have to set two fields: values, which is the List of filter matches, and count, which is basically the number of matcher (List.size()).
protected void publishResults(CharSequence, FilterResults): There is where you'll be passed the FilterResults from performFiltering, and all you have to do is to call notifyDataSetChanged() if count > 0 or notifyDataSetInvalidated() otherwise.
And that's it.
Use like this.. it worked perfectly for me
private class ItemFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
String filterString = constraint.toString().toLowerCase();
FilterResults results = new FilterResults();
final ArrayList<HashMap<String, String>> list = all_details;
int count = list.size();
final ArrayList<HashMap<String, String>> newlist = new ArrayList<HashMap<String, String>>();
String filterableString;
for (int i = 0; i < count; i++) {
filterableString = list.get(i).get("prodname");
if (filterableString.toString().toLowerCase().contains(filterString)) {
newlist.add(list.get(i));
}
}
results.values = newlist;
results.count = newlist.size();
return results;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
if (results != null) {
if (results.count > 0) {
pt_details = new ArrayList<HashMap<String,String>>((ArrayList<HashMap<String, String>>) results.values) ;
} else {
pt_details.clear();
//pt_details = all_details;
}
} else {
pt_details = all_details;
}
notifyDataSetChanged();
}
}