如何在 Recycler View 中正确实现搜索
How to implement search in Recycler View properly
我有一个使用 Realm 数据库获取数据的 RecyclerView,我想在操作栏上实现一个 SearchView,它可以搜索 RecyclerView 的项目,这是我的代码,但我似乎做不到它有效。
这是菜单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"/>
activity
处的 onOptionsItemSelected
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);
}
}
我的适配器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();
}
}
您似乎在 setFilter 方法中使用 arrayList 而不是 data,使用 数据 代替
希望这个回答对您有所帮助 Mahmoud Omara
嗨,Mahmoud Omara,你在使用领域数据库吗?
在 Recyclerview 适配器中实现 Filterable 然后生成 @Override 方法 getFilter。
然后实现你自己的过滤器,就像我已经改变了你的适配器一样
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();
}
}
}
然后更改您的 activity class onQueryTextChange 方法
看起来像这样
adapter.getFilter().filter(s);
这是我的问题的解决方案
首先在 onCreateOptionsMenu 添加这个
@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);
}
搜索方法
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;
}
});
}
在适配器处编写的setFilter方法
public void setFilter(List<UserInfo> newList){
data=new ArrayList<>();
data.addAll(newList);
notifyDataSetChanged();
}
在您的适配器上实施可过滤 class。
覆盖 getFilter 方法。
@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;
}
在您的主 activity 上,创建您的搜索视图并对 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;
}
您可以在此处找到完整的教程和源代码。
Recyclerview with searchview
希望这个回答对您有所帮助。
首先,您需要创建两个 ArrayList
,即 oriList
保存原始列表和 modList
保存过滤后的数据。
private ArrayList<SingleData> modList;
private ArrayList<SingleData> original;
1. 在 constructer
中初始化了它们,或者在适配器中创建一个方法来设置你的值,如下所示
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. 创建了另一个处理搜索查询的方法:
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. 从 activity 或下面的片段中调用搜索方法
YOUR_ADAPTER_OBJECT.filter(PASS_SEARCH_TEXT_HERE);
4. SingleData
是一个 pojo class
public class SingleData{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
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;
}
});
在适配器中
public void setFilter(List<GetGoogleTemplesResponse.ResultsBean> list){
beans=new ArrayList<>();
beans.addAll(list);
notifyDataSetChanged();
}
我有一个使用 Realm 数据库获取数据的 RecyclerView,我想在操作栏上实现一个 SearchView,它可以搜索 RecyclerView 的项目,这是我的代码,但我似乎做不到它有效。
这是菜单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"/>
activity
处的 onOptionsItemSelectedpublic 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);
}
}
我的适配器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();
}
}
您似乎在 setFilter 方法中使用 arrayList 而不是 data,使用 数据 代替
希望这个回答对您有所帮助 Mahmoud Omara
嗨,Mahmoud Omara,你在使用领域数据库吗?
在 Recyclerview 适配器中实现 Filterable 然后生成 @Override 方法 getFilter。
然后实现你自己的过滤器,就像我已经改变了你的适配器一样
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();
}
}
}
然后更改您的 activity class onQueryTextChange 方法
看起来像这样
adapter.getFilter().filter(s);
这是我的问题的解决方案 首先在 onCreateOptionsMenu 添加这个
@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);
}
搜索方法
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;
}
});
}
在适配器处编写的setFilter方法
public void setFilter(List<UserInfo> newList){
data=new ArrayList<>();
data.addAll(newList);
notifyDataSetChanged();
}
在您的适配器上实施可过滤 class。 覆盖 getFilter 方法。
@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;
}
在您的主 activity 上,创建您的搜索视图并对 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;
}
您可以在此处找到完整的教程和源代码。 Recyclerview with searchview
希望这个回答对您有所帮助。
首先,您需要创建两个 ArrayList
,即 oriList
保存原始列表和 modList
保存过滤后的数据。
private ArrayList<SingleData> modList;
private ArrayList<SingleData> original;
1. 在 constructer
中初始化了它们,或者在适配器中创建一个方法来设置你的值,如下所示
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. 创建了另一个处理搜索查询的方法:
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. 从 activity 或下面的片段中调用搜索方法
YOUR_ADAPTER_OBJECT.filter(PASS_SEARCH_TEXT_HERE);
4. SingleData
是一个 pojo class
public class SingleData{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
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;
}
});
在适配器中
public void setFilter(List<GetGoogleTemplesResponse.ResultsBean> list){
beans=new ArrayList<>();
beans.addAll(list);
notifyDataSetChanged();
}