【问题标题】:How to implement search in Recycler View properly如何在 Recycler View 中正确实现搜索
【发布时间】:2018-06-14 19:34:45
【问题描述】:

我有一个使用 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"/>

活动中的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);
    }
}

我的适配器类

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();
}

}

【问题讨论】:

  • 这使用 Realm 从 SQLite 数据库中获取数据,哇,这很有趣,我有两个数据库,我想知道为什么?
  • 我的意思是来自领域,忘记 sqlite 的东西
  • 这里“action bar上的SearchView可以搜索RecyclerView的item”,阐述
  • 虽然不行
  • @MahmoudOmara 你找到解决办法了吗?

标签: android android-studio android-recyclerview realm searchview


【解决方案1】:
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();
}

【讨论】:

    【解决方案2】:

    希望这个答案会有所帮助。

    首先,您需要创建两个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();
        }
    

    **注意:**1。如果您不想更改原始列表数据,请使用 clone() 方法同时添加新列表。

    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 或 Fragment 调用搜索方法

      YOUR_ADAPTER_OBJECT.filter(PASS_SEARCH_TEXT_HERE);
    

    4. SingleData 是一个 pojo 类

    public class SingleData{
    
        private String name;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    

    【讨论】:

      【解决方案3】:

      在您的适配器类上实现可过滤。 覆盖 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;
          }
      

      在您的主要活动中,创建您的搜索视图并对 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

      【讨论】:

        【解决方案4】:

        这是我的问题的解决方案 首先在 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();
        }
        

        【讨论】:

          【解决方案5】:

          我希望这个答案可以帮助你 Mahmoud Omara

          您好 Mahmoud Omara,您在使用领域数据库吗?

          在 Recyclerview 适配器中实现 Filterable 然后生成 @Override Method 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();
          
          
              }
          }
          }
          

          然后更改您的活动类 onQueryTextChange 方法

          看起来像这样

           adapter.getFilter().filter(s);
          

          【讨论】:

            【解决方案6】:

            您似乎在 setFilter 方法中使用 arrayList 而不是 data,请改用 data

            【讨论】:

              猜你喜欢
              • 2023-04-02
              • 1970-01-01
              • 1970-01-01
              • 2021-10-18
              • 1970-01-01
              • 2019-11-11
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多