SearchView 过滤和设置建议

Posted

技术标签:

【中文标题】SearchView 过滤和设置建议【英文标题】:SearchView Filtering and Set Suggestions 【发布时间】:2015-01-03 08:32:01 【问题描述】:

我对使用SearchView 很陌生。我需要一个有ActionBar 的功能,我有Search。当我点击搜索时,Suggestions 应该会显示在 Search 字段下方的 List 中。

到目前为止我做了什么: 在 menu.xml 中添加了搜索,并在 onCreateOptionsMenu() 中编写了代码,我在其中初始化了 SearchView,setSuggestionsAdapter 也实现了 setOnQueryTextListener

结果:我进入应用程序,点击搜索图标,它会显示建议。我输入一个字母,它会整理出匹配的字母。我输入第二个字母它没有显示任何建议。另外我关闭搜索视图并再次打开它,键盘已打开,但未显示列表中的建议。

我需要什么:根据用户输入的字符进行过滤。哪怕不止一个角色。 始终显示包含所有列表项的默认建议或在用户键入时排序的建议。

我在 android 的 SearchView 类中看到,他们将文本设置为空并且还关闭了建议。但我不想要这个。

我被困在这里,不知道如何继续。请帮我。 这是我的适配器代码:

public class ExampleAdapter extends CursorAdapter implements Filterable 

    private ArrayList<String> items;
    private ArrayList<String> orig;

    public ExampleAdapter(Context context, Cursor cursor,
            ArrayList<String> items) 
        super(context, cursor, false);
        this.items = new ArrayList<String>();
        this.items = items;
        orig = new ArrayList<String>();
        orig.addAll(items);
    

    @Override
    public int getCount() 
        return items.size();
    

    @Override
    public Filter getFilter() 
        return new Filter() 

            @Override
            protected FilterResults performFiltering(CharSequence constraint) 
                constraint = constraint.toString().toLowerCase();
                FilterResults result = new FilterResults();

                if (constraint != null
                        && constraint.toString().length() > 0) 
                    List<String> founded = new ArrayList<String>();
                    for (int i = 0, l = orig.size(); i < l; i++) 
                        if (orig.get(i)
                                .toString()
                                .toLowerCase()
                                .startsWith(
                                        constraint.toString().toLowerCase()))
                            founded.add(orig.get(i));
                    

                    result.values = founded;
                    result.count = founded.size();
                 else 
                    synchronized (this) 
                        result.values = orig;
                        result.count = orig.size();
                    

                
                return result;

            

            @Override
            protected void publishResults(CharSequence constraint,
                    FilterResults results) 

                items.clear();
                items = new ArrayList<String>();
                items = (ArrayList<String>) results.values;
                notifyDataSetChanged();

            

        ;
    

    @Override
    public void bindView(View view, Context context, Cursor cursor) 
        ViewHolder holder = (ViewHolder) view.getTag();
        holder.textView.setText(items.get(cursor.getPosition()));
    

    public class ViewHolder 
        public TextView textView;
    

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) 
        ViewHolder holder = new ViewHolder();
        View v = null;

        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        v = inflater.inflate(R.layout.item, parent, false);
        holder.textView = (TextView) v.findViewById(R.id.text);

        v.setTag(holder);
        return v;

    

我的 Activity 中的代码与我有 searchview 的菜单相关:

private String[] columns = new String[]  "_id", "text" ;
    private SearchView searchView;
    private SearchManager manager;
    private ExampleAdapter aptr;

@Override
    protected void onCreate(Bundle savedInstanceState) 
          super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_home);

    manager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);



@Override
    public boolean onCreateOptionsMenu(Menu menu) 
        getMenuInflater().inflate(R.menu.main, menu);
        MenuItem searchItem = menu.findItem(R.id.action_search);
        searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
        setSearchTextColour(searchView);
        setSearchIcons(searchView);
        searchView.setQueryHint(html.fromHtml("<font color = #ffffff>"
                + getResources().getString(R.string.search_store) + "</font>"));
        searchView.setSearchableInfo(manager
                .getSearchableInfo(getComponentName()));
        Object[] temp = new Object[]  0, "default" ;
        final MatrixCursor cursor = new MatrixCursor(columns);
        for (int i = 0; i < alStoreNames.size(); i++) 
            temp[0] = i;
            temp[1] = alStoreNames.get(i);
            cursor.addRow(temp);
        
        aptr = new ExampleAdapter(MainActivity.this, cursor, alStoreNames);
        searchView.setSuggestionsAdapter(aptr);

    searchView.setOnQueryTextListener(new OnQueryTextListener() 

        @Override
        public boolean onQueryTextSubmit(String arg0) 
            if (!TextUtils.isEmpty(arg0)) 
                aptr.getFilter().filter(arg0.toString());
            
            return true;
        

        @Override
        public boolean onQueryTextChange(String arg0) 
            return false;
        
    );

    searchView.setOnSuggestionListener(new OnSuggestionListener() 

            @Override
            public boolean onSuggestionSelect(int arg0) 
                return false;
            

            @Override
            public boolean onSuggestionClick(int position) 
                String suggestion = getSuggestion(position);
                db.openDatabase();
                String studentId = db.getStudentIdFromName(suggestion);
                String studentImg = db.getStudentImgFromName(suggestion);
                db.closeDatabase();
                Log.e("Sp", " On Click name -> " + aptr.getItem(position).toString() + " : "
                         + aptr.getCursor().getString(0) + " : " + suggestion);
                Intent i = new Intent(MainActivity.this,
                        ExampleActivity.class);
                i.putExtra("studentId", studentId);
                i.putExtra("studentName", suggestion);
                i.putExtra("studentImg", studentImg);
                startActivity(i);
                return true;
            
        );

    return true;


private String getSuggestion(int position) 
    Cursor cursor = (Cursor) searchView.getSuggestionsAdapter().getItem(
            position);
    String suggest1 = cursor.getString(cursor.getColumnIndex("text"));
    return suggest1;


private void setSearchTextColour(SearchView searchView) 
        Field qTextField;
        try 
            qTextField = SearchView.class.getDeclaredField("mQueryTextView");
            qTextField.setAccessible(true);
            SearchAutoComplete searchPlate = (SearchAutoComplete) qTextField
                    .get(searchView);
            searchPlate.setTextColor(getResources().getColor(R.color.white));
         catch (NoSuchFieldException e) 
            e.printStackTrace();
        
        catch (IllegalArgumentException e) 
            e.printStackTrace();
         catch (IllegalAccessException e) 
            e.printStackTrace();
        
    

private void setSearchIcons(SearchView searchView) 
    try 
        Field searchField = SearchView.class
                .getDeclaredField("mCloseButton");
        searchField.setAccessible(true);
        ImageView closeBtn = (ImageView) searchField.get(searchView);
        closeBtn.setImageResource(R.drawable.close);

        Field searchField1 = SearchView.class
                .getDeclaredField("mSearchButton");
        searchField1.setAccessible(true);
        ImageView searchButton = (ImageView) searchField1.get(searchView);
        searchButton.setImageResource(R.drawable.ic_action_search);

     catch (NoSuchFieldException e) 
        Log.e("SearchView", e.getMessage(), e);
     catch (IllegalAccessException e) 
        Log.e("SearchView", e.getMessage(), e);
    

【问题讨论】:

有什么变化?过滤没有问题..问题在于 onsuggestionclick 检查:***.com/questions/23422072/… 【参考方案1】:

在我看来,部分问题在于缺少 getItem() 方法。

如果您查看游标适配器源代码,getItem() 将从游标获取数据,而不是从过滤列表中获取数据,您希望它从过滤列表中获取数据!

试试这个:

@Override
 public Object getItem(int position) 
    if (position < items.size())             
        return items.get(position);
     else 
        return null;
    

我忘记添加了,你也需要改一下:

private String getSuggestion(int position) 
    String suggest1 = (String) searchView.getSuggestionsAdapter().getItem(position);    
    return suggest1;

要关闭所有内容,首先将其添加到 createOptions 菜单:

@Override
public boolean onCreateOptionsMenu(Menu menu) 
    getMenuInflater().inflate(R.menu.main, menu);
    MenuItem searchItem = menu.findItem(R.id.action_search);
    searchView = (SearchView) MenuItemCompat.getActionView(searchItem);

    searchView.setIconifiedByDefault(true); //this line

    ...

然后将其添加到 onSuggestionClick:

 @Override
 public boolean onSuggestionClick(int position) 
   String suggestion = getSuggestion(position);
   db.openDatabase();
   String studentId = db.getStudentIdFromName(suggestion);
   String studentImg = db.getStudentImgFromName(suggestion);
   db.closeDatabase();
   Log.e("Sp", " On Click name -> " + aptr.getItem(position).toString() + " : "
        + aptr.getCursor().getString(0) + " : " + suggestion);

   searchView.setIconified(true);//this line


   Intent i = new Intent(MainActivity.this,ExampleActivity.class);
   i.putExtra("studentId", studentId);
   i.putExtra("studentName", suggestion);
   i.putExtra("studentImg", studentImg);
   startActivity(i);
   return true;

有点解释。当您调用 setIconified 时,它将清除您的 searchView 的文本或将其折叠,具体取决于默认状态。我们所做的是将默认状态设置为图标化,因此当我们调用 setIconified 方法时,它将清除文本并折叠视图!

【讨论】:

【参考方案2】:

您好,我发现您的代码存在一些问题。 请尝试我的方式。 替换publishResults of ExampleAdapter

 @Override
            protected void publishResults(CharSequence constraint,
                    FilterResults results) 

                items.clear();
                 // items = new ArrayList<String>();
                //items = (ArrayList<String>) results.values;
                items.addAll((ArrayList<String>) results.values);
                notifyDataSetChanged();

            

    searchView.setOnQueryTextListener(new OnQueryTextListener() 

        @Override
        public boolean onQueryTextSubmit(String arg0) 
            if (!TextUtils.isEmpty(arg0)) 
                aptr.getFilter().filter(arg0.toString());
            
            return true;
        

        @Override
        public boolean onQueryTextChange(String arg0) 
if (!TextUtils.isEmpty(arg0)) 
                aptr.getFilter().filter(arg0.toString());
return true;
            
            return false;
        
    );

【讨论】:

解决了建议列表问题。但是当我单击排序建议列表中的一项时,它指向该位置的旧字符串 将 cursoradapter 设为全局并尝试使用 adapter.getItem(position); 我有 onSuggestionClick,当我点击它时,它会给出点击的字符串名称 必须尝试将适配器设为全局?【参考方案3】:

尝试将搜索值传递给过滤器,即使是空的:

@Override
public boolean onQueryTextSubmit(String arg0) 
     aptr.getFilter().filter(arg0.toString());
     return true;

如果搜索不匹配或搜索值为空,则将默认列表设置为适配器:

@Override
public Filter getFilter() 
   return new Filter() 
   @Override
   protected FilterResults performFiltering(CharSequence constraint) 
      constraint = constraint.toString().toLowerCase();
      FilterResults result = new FilterResults();

      if (constraint != null && constraint.toString().length() > 0) 
          List<String> founded = new ArrayList<String>();
          for (int i = 0, l = orig.size(); i < l; i++) 
               if (orig.get(i).toString().toLowerCase().startsWith(constraint.toString().toLowerCase()))
                            founded.add(orig.get(i));
          

          if(founded.size()>0)
             result.values = founded;
             result.count = founded.size();
          else
             result.values = orig;
             result.count = orig.size();
          
       else 
             result.values = orig;
             result.count = orig.size();
      
      return result;


【讨论】:

以上是关于SearchView 过滤和设置建议的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 SearchView 过滤 RecyclerView

使用 Room 和 RecyclerView 在 SearchView 中添加过滤器

如何使用 SearchView 过滤 FirestoreRecyclerAdapter

我的应用程序的Recycler View问题中的Android Studio SearchView过滤器

已解决:SearchView 不会在 TabLayout 的每个子选项卡中进行过滤

在使用存储在 JSON 上的 ID 进行 SearchView 过滤后,如何从 ListView 打开 Activity