在操作栏中实现 SearchView
Posted
技术标签:
【中文标题】在操作栏中实现 SearchView【英文标题】:Implementing SearchView in action bar 【发布时间】:2014-03-02 08:39:30 【问题描述】:我需要从我的arrayList<String>
创建SearchView
并在下拉列表中显示与此相同的建议
我正在寻找逐步解释如何在操作栏中构建SearchView
的教程。
我已阅读 the documentation 并按照示例 google 但它对我没有用。
我已经创建了搜索
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/action_search"
android:title="Search"
android:icon="@android:drawable/ic_menu_search"
android:showAsAction="always"
android:actionViewClass="android.widget.SearchView" />
</menu>`
但是我不知道如何设置字符串数组的参数。 我试图在不同的 Activity 中检索结果,但不起作用。
【问题讨论】:
您应该尽可能详细地发布您尝试过的所有内容。带有示例代码的具体问题往往会得到更快、更有意义的答案。 【参考方案1】:为此制定解决方案需要一段时间,但发现这是使其以您描述的方式工作的最简单方法。可能有更好的方法来做到这一点,但由于您尚未发布您的活动代码,我将不得不即兴发挥并假设您在活动开始时有这样的列表:
private List<String> items = db.getItems();
ExampleActivity.java
private List<String> items;
private Menu menu;
@Override
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public boolean onCreateOptionsMenu(Menu menu)
getMenuInflater().inflate(R.menu.example, menu);
this.menu = menu;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
SearchManager manager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView search = (SearchView) menu.findItem(R.id.search).getActionView();
search.setSearchableInfo(manager.getSearchableInfo(getComponentName()));
search.setOnQueryTextListener(new OnQueryTextListener()
@Override
public boolean onQueryTextChange(String query)
loadHistory(query);
return true;
);
return true;
// History
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void loadHistory(String query)
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
// Cursor
String[] columns = new String[] "_id", "text" ;
Object[] temp = new Object[] 0, "default" ;
MatrixCursor cursor = new MatrixCursor(columns);
for(int i = 0; i < items.size(); i++)
temp[0] = i;
temp[1] = items.get(i);
cursor.addRow(temp);
// SearchView
SearchManager manager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
final SearchView search = (SearchView) menu.findItem(R.id.search).getActionView();
search.setSuggestionsAdapter(new ExampleAdapter(this, cursor, items));
现在你需要创建一个扩展自CursorAdapter
的适配器:
ExampleAdapter.java
public class ExampleAdapter extends CursorAdapter
private List<String> items;
private TextView text;
public ExampleAdapter(Context context, Cursor cursor, List<String> items)
super(context, cursor, false);
this.items = items;
@Override
public void bindView(View view, Context context, Cursor cursor)
text.setText(items.get(cursor.getPosition()));
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent)
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.item, parent, false);
text = (TextView) view.findViewById(R.id.text);
return view;
更好的方法是,如果您的列表数据来自数据库,您可以将数据库函数返回的Cursor
直接传递给ExampleAdapter
,并使用相关的列选择器在@987654329 中显示列文本@ 在适配器中引用。
请注意:导入CursorAdapter
时不要导入Android支持版本,而是导入标准android.widget.CursorAdapter
。
适配器还需要自定义布局:
res/layout/item.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_>
<TextView
android:id="@+id/item"
android:layout_
android:layout_ />
</RelativeLayout>
您现在可以通过向布局添加额外的文本或图像视图并使用适配器中的数据填充它们来自定义列表项。
这应该是全部,但如果你还没有这样做,你需要一个 SearchView 菜单项:
res/menu/example.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/search"
android:title="@string/search"
android:showAsAction="ifRoom"
android:actionViewClass="android.widget.SearchView" />
</menu>
然后创建一个可搜索的配置:
res/xml/searchable.xml
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/search"
android:hint="@string/search" >
</searchable>
最后在清单文件的相关活动标签中添加这个:
AndroidManifest.xml
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data
android:name="android.app.default_searchable"
android:value="com.example.ExampleActivity" />
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable" />
请注意:示例中使用的@string/search
字符串应在values/strings.xml 中定义,也不要忘记为您的项目更新对com.example
的引用。
【讨论】:
您好,但有一个疑问,我希望您能帮助我解决这个问题。如果我在过滤器上键入一个字母,虽然我有过滤结果,但如果超过一个,则不会显示任何内容。然后只有它显示。为什么? 您好,请检查您的样式是否有任何与 EditText 或 AutoCompleteTextView 相关的内容,因为您可以设置在显示自动完成之前需要输入的默认字符数。实际上我认为默认值是 2 个字符,因此您可能需要将其添加到样式中才能更改它。 您好,在开发过程中,我又遇到了一期 searchview。如果我在下拉列表中显示更多项目,例如:3 个文本视图,则项目的大小会增加,因此如果我像 i.stack.imgur.com/d7t3A.png 一样滚动,搜索项目会在键盘上流动。如果我增加文本大小或在项目中添加更多视图,就会发生这种情况。这是默认行为吗? 再次嗨,不,这不应该发生。听起来您的项目中已经有很多代码干扰了 SearchView 中的 AutoCompleteTextView,或者键盘软件、应用程序或插件可能有问题导致了这种行为。默认行为应该是这样的 ***.com/questions/22116237/… 除了这个人实际上是在问如何让它不隐藏在键盘后面。 @tpbapp 我已经弄清楚了。没有出现建议列表的原因是因为在您的代码中,您在onCreateOptionsMenu()
和 loadHistory()
方法中调用了两次 search.setSearchableInfo(manager.getSearchableInfo(getComponentName()));
。所以我创建了 SearchView 和 SearchManager 全局变量,并且只在 onCreateOptionsMenu()
中调用了一次 getSearchableInfo()
。我的建议清单现在运行良好。我建议你修改你的代码。【参考方案2】:
如果其他人在 searchview 变量上有一个 nullptr,我发现项目设置有点不同:
旧:
android:showAsAction="ifRoom"
android:actionViewClass="android.widget.SearchView"
新:
app:showAsAction="ifRoom|collapseActionView"
app:actionViewClass="androidx.appcompat.widget.SearchView"
pre-android x:
app:showAsAction="ifRoom|collapseActionView"
app:actionViewClass="android.support.v7.widget.SearchView"
更多信息,它的更新文档是located here。
【讨论】:
谢谢。正是我所缺少的。 :-) 谢谢你,这很简单而且很有帮助。app:actionViewClass="androidx.appcompat.widget.SearchView"
for androidx【参考方案3】:
SearchDialog 还是 SearchWidget?
在实现搜索功能时,官方 Android 开发者文档中有 two suggested approach。 您可以使用 SearchDialog 或 SearchWidget。 我将解释使用 SearchWidget 实现搜索功能。
如何使用搜索小部件?
我将使用 SearchWidget 在 RecyclerView 中解释搜索功能。这很简单。
只需遵循这 5 个简单步骤
1) 在菜单中添加 searchView 项
您可以在菜单中添加SearchView
可以添加为actionView
使用
app:useActionClass = "android.support.v7.widget.SearchView" .
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="rohksin.com.searchviewdemo.MainActivity">
<item
android:id="@+id/searchBar"
app:showAsAction="always"
app:actionViewClass="android.support.v7.widget.SearchView"
/>
</menu>
2) 设置 SerchView 提示文本、监听器等
您应该在 onCreateOptionsMenu(Menu menu)
方法中初始化 SearchView。
@Override
public boolean onCreateOptionsMenu(Menu menu)
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
MenuItem searchItem = menu.findItem(R.id.searchBar);
SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setQueryHint("Search People");
searchView.setOnQueryTextListener(this);
searchView.setIconified(false);
return true;
3) 在 Activity 中实现 SearchView.OnQueryTextListener
OnQueryTextListener
有两个抽象方法
onQueryTextSubmit(String query)
onQueryTextChange(String newText
所以你的 Activity 骨架应该是这样的
YourActivity extends AppCompatActivity implements SearchView.OnQueryTextListener
public boolean onQueryTextSubmit(String query)
public boolean onQueryTextChange(String newText)
4) 实现 SearchView.OnQueryTextListener
你可以像这样提供抽象方法的实现
public boolean onQueryTextSubmit(String query)
// This method can be used when a query is submitted eg. creating search history using SQLite DB
Toast.makeText(this, "Query Inserted", Toast.LENGTH_SHORT).show();
return true;
@Override
public boolean onQueryTextChange(String newText)
adapter.filter(newText);
return true;
5) 在您的 RecyclerView Adapter 中编写一个过滤器方法。
最重要的部分。您可以编写自己的逻辑来执行搜索。
这是我的。此 sn-p 显示名称列表,其中包含在 SearchView
中键入的文本
public void filter(String queryText)
list.clear();
if(queryText.isEmpty())
list.addAll(copyList);
else
for(String name: copyList)
if(name.toLowerCase().contains(queryText.toLowerCase()))
list.add(name);
notifyDataSetChanged();
相关链接:
在 Music App 中使用 SQLite 数据库的 SearchView 上的完整工作代码
【讨论】:
【参考方案4】:Searchview
使用这些代码
对于 XML
<android.support.v7.widget.SearchView
android:layout_
android:layout_
android:id="@+id/searchView">
</android.support.v7.widget.SearchView>
在您的片段或活动中
package com.example.user.salaryin;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SearchView;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import com.example.user.salaryin.Adapter.BusinessModuleAdapter;
import com.example.user.salaryin.Network.ApiClient;
import com.example.user.salaryin.POJO.ProductDetailPojo;
import com.example.user.salaryin.Service.ServiceAPI;
import java.util.ArrayList;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class OneFragment extends Fragment implements SearchView.OnQueryTextListener
RecyclerView recyclerView;
RecyclerView.LayoutManager layoutManager;
ArrayList<ProductDetailPojo> arrayList;
BusinessModuleAdapter adapter;
private ProgressDialog pDialog;
GridLayoutManager gridLayoutManager;
SearchView searchView;
public OneFragment()
// Required empty public constructor
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
View rootView = inflater.inflate(R.layout.one_fragment,container,false);
pDialog = new ProgressDialog(getActivity());
pDialog.setMessage("Please wait...");
searchView=(SearchView)rootView.findViewById(R.id.searchView);
searchView.setQueryHint("Search BY Brand");
searchView.setOnQueryTextListener(this);
recyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerView);
layoutManager = new LinearLayoutManager(this.getActivity());
recyclerView.setLayoutManager(layoutManager);
gridLayoutManager = new GridLayoutManager(this.getActivity().getApplicationContext(), 2);
recyclerView.setLayoutManager(gridLayoutManager);
recyclerView.setHasFixedSize(true);
getImageData();
// Inflate the layout for this fragment
//return inflater.inflate(R.layout.one_fragment, container, false);
return rootView;
private void getImageData()
pDialog.show();
ServiceAPI service = ApiClient.getRetrofit().create(ServiceAPI.class);
Call<List<ProductDetailPojo>> call = service.getBusinessImage();
call.enqueue(new Callback<List<ProductDetailPojo>>()
@Override
public void onResponse(Call<List<ProductDetailPojo>> call, Response<List<ProductDetailPojo>> response)
if (response.isSuccessful())
arrayList = (ArrayList<ProductDetailPojo>) response.body();
adapter = new BusinessModuleAdapter(arrayList, getActivity());
recyclerView.setAdapter(adapter);
pDialog.dismiss();
else if (response.code() == 401)
pDialog.dismiss();
Toast.makeText(getActivity(), "Data is not found", Toast.LENGTH_SHORT).show();
@Override
public void onFailure(Call<List<ProductDetailPojo>> call, Throwable t)
Toast.makeText(getActivity(), t.getMessage(), Toast.LENGTH_SHORT).show();
pDialog.dismiss();
);
/* @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
getActivity().getMenuInflater().inflate(R.menu.menu_search, menu);
MenuItem menuItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) MenuItemCompat.getActionView(menuItem);
searchView.setQueryHint("Search Product");
searchView.setOnQueryTextListener(this);
*/
@Override
public boolean onQueryTextSubmit(String query)
return false;
@Override
public boolean onQueryTextChange(String newText)
newText = newText.toLowerCase();
ArrayList<ProductDetailPojo> newList = new ArrayList<>();
for (ProductDetailPojo productDetailPojo : arrayList)
String name = productDetailPojo.getDetails().toLowerCase();
if (name.contains(newText) )
newList.add(productDetailPojo);
adapter.setFilter(newList);
return true;
在适配器类中
public void setFilter(List<ProductDetailPojo> newList)
arrayList=new ArrayList<>();
arrayList.addAll(newList);
notifyDataSetChanged();
【讨论】:
以上是关于在操作栏中实现 SearchView的主要内容,如果未能解决你的问题,请参考以下文章