设置搜索界面

从 Android 3.0 开始,将 SearchView 微件作为应用栏中的一个项,是在应用中提供搜索机制的首选方式。与应用栏中的所有项一样,您可以将 SearchView 设定为始终显示、仅在有空间时显示,也可以将其设定为一个可收起操作项,这最初会将 SearchView 显示为一个图标,然后当用户点击该图标时,它会以搜索字段的形式占据整个应用栏的空间。

注意:在本节课后面的部分中,您将了解对于不支持 SearchView 的设备,如何使您的应用与最低为 Android 2.1(API 级别 7)的版本兼容。

将搜索视图添加到应用栏

要将 SearchView 微件添加到应用栏,请在您的项目中创建一个名为 res/menu/options_menu.xml 的文件,并将以下代码添加到该文件中。该代码定义了如何创建搜索项,例如要使用的图标和项的名称。通过 collapseActionView 属性,您的 SearchView 可以展开以占据整个应用栏的空间,并在未使用时重新收起为一个普通的应用栏项。由于手机设备上的应用栏空间有限,建议使用 collapsibleActionView 属性,以提供更出色的用户体验。

    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:id="@+id/search"
              android:title="@string/search_title"
              android:icon="@drawable/ic_search"
              android:showAsAction="collapseActionView|ifRoom"
              android:actionViewClass="android.widget.SearchView" />
    </menu>
    

注意:如果您已有菜单项的现有 XML 文件,则可以改为将 <item> 元素添加到该文件中。

要在应用栏中显示 SearchView,请在 Activity 的 onCreateOptionsMenu() 方法中扩充 XML 菜单资源 (res/menu/options_menu.xml):

Kotlin

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        menuInflater.inflate(R.menu.options_menu, menu)

        return true
    }
    

Java

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.options_menu, menu);

        return true;
    }
    

如果您现在运行应用,会在应用栏中看到 SearchView,但它不起作用。您现在需要定义 SearchView 的行为方式。

创建可搜索配置

可搜索配置res/xml/searchable.xml 文件中定义了 SearchView 的行为方式。可搜索配置必须至少包含一个 android:label 属性,其值与您的 Android 清单中 <application><activity> 元素的 android:label 属性的值相同。不过,我们还建议您添加一个 android:hint 属性,以便用户了解可在搜索框中输入的内容:

    <?xml version="1.0" encoding="utf-8"?>

    <searchable xmlns:android="http://schemas.android.com/apk/res/android"
            android:label="@string/app_name"
            android:hint="@string/search_hint" />
    

在应用的清单文件中,声明一个指向 res/xml/searchable.xml 文件的 <meta-data> 元素,以便您的应用知道可以在何处找到该文件。在您要显示 SearchView<activity> 中声明该元素:

    <activity ... >
        ...
        <meta-data android:name="android.app.searchable"
                android:resource="@xml/searchable" />

    </activity>
    

在您之前创建的 onCreateOptionsMenu() 方法中,通过调用 setSearchableInfo(SearchableInfo) 将可搜索配置与 SearchView 相关联:

Kotlin

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        menuInflater.inflate(R.menu.options_menu, menu)

        // Associate searchable configuration with the SearchView
        val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
        (menu.findItem(R.id.search).actionView as SearchView).apply {
            setSearchableInfo(searchManager.getSearchableInfo(componentName))
        }

        return true
    }
    

Java

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.options_menu, menu);

        // Associate searchable configuration with the SearchView
        SearchManager searchManager =
               (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        SearchView searchView =
                (SearchView) menu.findItem(R.id.search).getActionView();
        searchView.setSearchableInfo(
                searchManager.getSearchableInfo(getComponentName()));

        return true;
    }
    

调用 getSearchableInfo() 可获取从可搜索配置 XML 文件中创建的 SearchableInfo 对象。可搜索配置与您的 SearchView 正确关联后,SearchView 会在用户提交查询时使用 ACTION_SEARCH intent 启动 Activity。现在,您需要一个可以过滤此 intent 并处理搜索查询的 Activity。

创建可搜索 Activity

当用户提交搜索查询时,SearchView 会尝试使用 ACTION_SEARCH 启动 Activity。可搜索 Activity 可以过滤 ACTION_SEARCH intent,并在某种数据集中搜索查询。要创建可搜索 Activity,请声明一个您选择用于过滤 ACTION_SEARCH intent 的 Activity:

    <activity android:name=".SearchResultsActivity" ... >
        ...
        <intent-filter>
            <action android:name="android.intent.action.SEARCH" />
        </intent-filter>
        ...
    </activity>
    

在您的可搜索 Activity 中,通过在 onCreate() 方法中检查 ACTION_SEARCH intent 对其进行处理。

注意:如果您的可搜索 Activity 会在单一顶级模式 (android:launchMode="singleTop") 下启动,请也在 onNewIntent() 方法中处理 ACTION_SEARCH intent。在单一顶级模式下,只能创建 Activity 的一个实例,启动 Activity 的后续调用不会在堆栈上创建新的 Activity。该启动模式非常实用,用户可以通过同一 Activity 执行搜索,而无需每次都创建新的 Activity 实例。

Kotlin

    class SearchResultsActivity : Activity() {

        override fun onCreate(savedInstanceState: Bundle?) {
            ...
            handleIntent(intent)
        }

        override fun onNewIntent(intent: Intent) {
            ...
            handleIntent(intent)
        }

        private fun handleIntent(intent: Intent) {

            if (Intent.ACTION_SEARCH == intent.action) {
                val query = intent.getStringExtra(SearchManager.QUERY)
                //use the query to search your data somehow
            }
        }
        ...
    }
    

Java

    public class SearchResultsActivity extends Activity {

        @Override
        public void onCreate(Bundle savedInstanceState) {
            ...
            handleIntent(getIntent());
        }

        @Override
        protected void onNewIntent(Intent intent) {
            ...
            handleIntent(intent);
        }

        private void handleIntent(Intent intent) {

            if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
                String query = intent.getStringExtra(SearchManager.QUERY);
                //use the query to search your data somehow
            }
        }
        ...
    }
    

如果您现在运行应用,SearchView 可以接受用户的查询,并使用 ACTION_SEARCH intent 启动您的可搜索 Activity。现在,您需要确定如何针对查询存储和搜索您的数据。