Reputation:
i have a RecyclerView that is taking the data using Realm database, i want to implement a SearchView on the action bar that can search through the items of the RecyclerView, this is my code but i can't seem to make it work.
here's the menu XML
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/action_search"
android:icon="@drawable/ic_search_white_24dp"
android:title="Search"
app:actionViewClass="android.support.v7.widget.SearchView"
app:showAsAction="ifRoom"/>
<item android:id="@+id/action_add"
android:icon="@drawable/ic_add_white_48dp"
android:title="Add"
app:showAsAction="ifRoom"/>
the onOptionsItemSelected at the activity
public boolean onOptionsItemSelected(MenuItem item) {
// Take appropriate action for each action item click
switch (item.getItemId()) {
case R.id.action_search:
// search action
SearchView searchView=(SearchView)item.getActionView();
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
//adapter.getFilter().filter(query);
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
//adapter.getFilter().filter(newText);
newText=newText.toLowerCase();
System.out.println(results);
ArrayList<UserInfo> newList=new ArrayList<>();
for (UserInfo userInfo : results){
String username=userInfo.getUsername().toLowerCase();
String password=userInfo.getPassword().toLowerCase();
String type=userInfo.getType().toLowerCase();
if (username.contains(newText)||password.contains(newText)||type.contains(newText)){
newList.add(userInfo);
}
}
adapter.setFilter(newList);
return true;
}
});
return true;
case R.id.action_add:
addInfo();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
my Adapter class
public class Adapter extends RecyclerView.Adapter<Adapter.MyViewHolder> {
private LayoutInflater layoutInflater;
java.util.List<UserInfo> data= Collections.emptyList();
ArrayList<UserInfo> arrayList;
public Adapter(Context context, java.util.List<UserInfo> data){
layoutInflater=LayoutInflater.from(context);
this.data=data;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view=layoutInflater.inflate(R.layout.list_item , parent,false);
MyViewHolder holder=new MyViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
UserInfo current=data.get(position);
holder.username.setText("Username: "+current.username);
holder.password.setText("Password: "+current.password);
holder.type.setText("Type: "+current.type);
}
@Override
public int getItemCount() {
return data.size();
}
class MyViewHolder extends RecyclerView.ViewHolder{
TextView username,password,type;
public MyViewHolder(View itemView) {
super(itemView);
username= (TextView) itemView.findViewById(R.id.username_TV);
password= (TextView) itemView.findViewById(R.id.password_TV);
type= (TextView) itemView.findViewById(R.id.type_TV);
}
}
public void setFilter(List<UserInfo> newList){
arrayList=new ArrayList<>();
arrayList.addAll(newList);
notifyDataSetChanged();
}
}
Upvotes: 0
Views: 8526
Reputation: 11
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String s) {
return true;
}
@Override
public boolean onQueryTextChange(String s) {
searchKeyword = s;
s=s.toLowerCase();
ArrayList<GetGoogleTemplesResponse.ResultsBean> temples=new ArrayList<>();
for (GetGoogleTemplesResponse.ResultsBean bean : results){
String templeName=bean.getName().toLowerCase();
if (templeName.contains(s)){
temples.add(bean);
}
}
adapter.setFilter(temples);
return true;
}
});
In adapter
public void setFilter(List<GetGoogleTemplesResponse.ResultsBean> list){
beans=new ArrayList<>();
beans.addAll(list);
notifyDataSetChanged();
}
Upvotes: 0
Reputation: 3928
Hope this answer will help SO.
First of all, you need to create two ArrayList
i.e oriList
hold original list and modList
hold filtered data.
private ArrayList<SingleData> modList;
private ArrayList<SingleData> original;
1. Initialized both of them in the constructer
Or create a method in the adapter to set your value like below
public void setEmployees(ArrayList<SingleData> dataList) {
this.dataList = new ArrayList<>();
this.dataList = dataList;
oriDataList = new ArrayList<>();
oriDataList = (ArrayList<SingleData>) dataList.clone();
notifyDataSetChanged();
}
**Note:**1. If you don't want to change the original list data then use the
clone()
method while adding a new list.
2. Created a another method which will handle the search query:
public void filter(String text) {
dataList.clear();
if (text.isEmpty()) {
dataList.addAll(oriDataList);
} else {
text = text.toLowerCase();
for (SingleData item : oriDataList) {
if (item.getName().toLowerCase().contains(text)) {
dataList.add(item);
}
}
}
notifyDataSetChanged();
}
3. Call the search method from the activity or fragment like below
YOUR_ADAPTER_OBJECT.filter(PASS_SEARCH_TEXT_HERE);
4. SingleData
is a pojo class
public class SingleData{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Upvotes: 0
Reputation: 799
implement filterable on your adapter class. Override getFilter method.
@Override
public Filter getFilter() {
Filter filter = new Filter() {
@Override
protected FilterResults performFiltering(CharSequence charSequence) {
FilterResults filterResults = new FilterResults();
if(charSequence == null | charSequence.length() == 0){
filterResults.count = getUserModelListFiltered.size();
filterResults.values = getUserModelListFiltered;
}else{
String searchChr = charSequence.toString().toLowerCase();
List<UserModel> resultData = new ArrayList<>();
for(UserModel userModel: getUserModelListFiltered){
if(userModel.getUserName().toLowerCase().contains(searchChr)){
resultData.add(userModel);
}
}
filterResults.count = resultData.size();
filterResults.values = resultData;
}
return filterResults;
}
@Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
userModelList = (List<UserModel>) filterResults.values;
notifyDataSetChanged();
}
};
return filter;
}
On your main activity, create your searchview and perform filter on querytextchange.
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu, menu);
MenuItem menuItem = menu.findItem(R.id.search_view);
SearchView searchView = (SearchView) menuItem.getActionView();
searchView.setMaxWidth(Integer.MAX_VALUE);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
usersAdapter.getFilter().filter(newText);
return true;
}
});
return true;
}
you can find the full tutorial and source code here. Recyclerview with searchview
Upvotes: 0
Reputation:
this is the solution to my problem first at the onCreateOptionsMenu add this
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_actions, menu);
MenuItem search=menu.findItem(R.id.action_search);
//this 2 lines
SearchView searchView=(SearchView)search.getActionView();
search(searchView);
return super.onCreateOptionsMenu(menu);
}
the search method
private void search(SearchView searchView) {
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
newText=newText.toLowerCase();
ArrayList<UserInfo> newList=new ArrayList<>();
for (UserInfo userInfo : results){
String username=userInfo.getUsername().toLowerCase();
String password=userInfo.getPassword().toLowerCase();
String type=userInfo.getType().toLowerCase();
if (username.contains(newText)||password.contains(newText)||type.contains(newText)){
newList.add(userInfo);
}
}
adapter.setFilter(newList);
return true;
}
});
}
the setFilter method that is written at the adapter
public void setFilter(List<UserInfo> newList){
data=new ArrayList<>();
data.addAll(newList);
notifyDataSetChanged();
}
Upvotes: 2
Reputation: 339
I hope this answer helps you Mahmoud Omara
Hi Mahmoud Omara are you using realm database.
In Recyclerview adapter implement Filterable then generate @Override Method getFilter.
Then implement your own filter look like i have change your adapter
public class Adapter extends RecyclerView.Adapter<Adapter.MyViewHolder> implements Filterable {
private LayoutInflater layoutInflater;
java.util.List<UserInfo> data= Collections.emptyList();
public Adapter(Context context, java.util.List<UserInfo> data){
layoutInflater=LayoutInflater.from(context);
this.data=data;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view=layoutInflater.inflate(R.layout.list_item , parent,false);
MyViewHolder holder=new MyViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
UserInfo current=data.get(position);
holder.username.setText("Username: "+current.username);
holder.password.setText("Password: "+current.password);
holder.type.setText("Type: "+current.type);
}
@Override
public int getItemCount() {
return data.size();
}
class MyViewHolder extends RecyclerView.ViewHolder{
TextView username,password,type;
public MyViewHolder(View itemView) {
super(itemView);
username= (TextView) itemView.findViewById(R.id.username_TV);
password= (TextView) itemView.findViewById(R.id.password_TV);
type= (TextView) itemView.findViewById(R.id.type_TV);
}
}
@Override
public Filter getFilter() {
return new MyNamesFilter();
}
private class MyNamesFilter
extends Filter {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
return new FilterResults();
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
//myRealm is your realm object
//contactName is in your database column name replace your table name column
RealmResults<Contact> contactArrayLisst = myRealm.where(Contact.class)
.beginGroup()
.contains("contactName", constraint.toString(), Case.INSENSITIVE)
.endGroup()
.findAll();
data.clear();
data.addAll(contactArrayLisst);
notifyDataSetChanged();
}
}
}
Then changes your activity class onQueryTextChange Method
look like this
adapter.getFilter().filter(s);
Upvotes: 2
Reputation: 6697
It seems like you are using arrayList intstead of data in your setFilter method,use data instead
Upvotes: 0