为应用添加搜索功能

创建搜索对话框

自Androi3.0开始,Android移除了物理搜索键。因此必须在应用内部提供搜索键。
这里写图片描述

添加搜索菜单项fragment_photo_gallery.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:id="@+id/menu_item_search"
        android:icon="@android:drawable/ic_menu_search"
        android:showAsAction="ifRoom"
        android:title="@string/search"/>
    <item
        android:id="@+id/menu_item_clear"
        android:icon="@android:drawable/ic_menu_close_clear_cancel"
        android:showAsAction="ifRoom"
        android:title="@string/clear_search"/>

</menu>
实现菜单项
@Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        super.onCreateOptionsMenu(menu, inflater);
        inflater.inflate(R.menu.fragment_photo_gallery, menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.menu_item_search:
            /**
             * Activity.onSearchRequested()方法与点按搜索键执行的操作完全相同。
             */
            getActivity().onSearchRequested();
            return true;
        case R.id.menu_item_clear://撤销搜索
            PreferenceManager.getDefaultSharedPreferences(getActivity()).edit()
            .putString(FlickrFetchr.PREF_SEARCH_QUERY, null).commit();
            updateItems();
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

要使onSearchRequested()方法能够工作,我们必须设置Activity为可搜索activity。

第一步:创建新目录res/xml,并在其中创建一个名为searchable.xml的独立XML配置文件。该XML配置文件包含一个名为searchable的元素节点,用来描述搜索对话框应该如何显示自身。searchable.xml又称为搜索配置文件。

<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:hint="@string/search_hint"
    android:label="@string/app_name" />

第二步,在应用的AndroidManifest.xml配置文件中修改。首先需要更改activity的启动模式,其次需为activity 声明附加的intent filter以及元数据信息。intent filter表明应用可监听搜索intent,元数据信息则将searchable.xml 与目标activity关联起来。

 <activity
            android:name="com.example.photogallery.PhotoGalleryActivity"
            android:launchMode="singleTop"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.SEARCH" />
            </intent-filter>
            <meta-data android:name="android.app.searchable"
                android:resource="@xml/searchable"/>
        </activity>

通过以上文件配置工作,我们告诉Android的SearchManager,activity能够处理搜索任务,并同时将搜索配置信息提供给它。 SearchManager属于操作系统级别的服务,负责展现搜索对话框并管理搜索相关的交互。

注意,元数据中android:resource属性与android:value属性的区别,假定在两个不同的元数据标签中引用了同一个字符串资源:

<meta-data android:name="metadata.resource"
   android:resource="@string/app_name"/>
<meta-data android:name="metadata.value"
   android:value="@string/app_name"/>

倘若从元数据节点取出metadata.value的值,则会发现它包含了@string/app_name中保存的“PhotoGallery”字符串。而metadata.resource的值则会是资源的整数ID值。SearchManager需要的是searchable.xml资源的整数ID,而不是XML文件的字符串值。

搜索的工作原理

需要搜索时,按下搜索键,会触发一系列搜索交互,直到搜索intent自身由系统接手处理。SearchManager会检查AndroidManifest.xml,以确认当前activity是否支持搜索。如果支持,一个搜索对话框activity就会显示在当前activity上。然后,通过发送新的intent,搜索对话框activity触发搜索。

这意味着按钮搜索按钮通常会启动一个新的activity。但在当前应用中,系统并没有启动新的activity,这是因为添加了android:launchMode=”singleTop”后,我们改变了启动模式。

各种不同的启动模式

启动模式行为
standard默认行为模式。针对每一个收到的新intent,都启动新的activity
singleTop如果activity实例已经处在会退栈的顶端,则不创建新的activity,而直接把新intent给现有activity
singleTask在自身task中启动activity。如果task中国activity已存在,则清除会退栈中该activity上的任何activity,然后把新intent给现有activity
singleInstance在自身task中启动activity。该activity是task中唯一的activity。如果任何其他activity从该task中启动,它们都各自启动到自己的task中。如果task中activity以存在,则直接把新intent给现有activity

在Activity中覆盖onNewIntent(Intent)方法,以接收新的intent并刷新数据:

    /**
     * 如果需要新intent的值,切记将其存储起来。从getIntent()方法获取的是旧intent的值。
     * 这是因为getIntent()方法只返回启动了当前activity的intent,而非接收到的最新intent。
     */
    @Override
    protected void onNewIntent(Intent intent) {
        PhotoGalleryFragment fragment = (PhotoGalleryFragment) getSupportFragmentManager()
                .findFragmentById(R.id.fragmentContainer);

        if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
            String query = intent.getStringExtra(SearchManager.QUERY);
            Log.i(TAG, query);
            /**
             * 由于shared preferences共享与整个应用,我们使用PreferenceManager.getDefaultSharedPreferences(Context)
             * 方法,该方法会返回具有私有权限与默认名称的实例。
             */
            PreferenceManager.getDefaultSharedPreferences(this).edit()
                    .putString(FlickrFetchr.PREF_SEARCH_QUERY, query).commit();
        }

        fragment.updateItems();
    }

在Android3.0以后版本的设备上使用SearchView

这里写图片描述

SearchView属于操作视图。可内置在操作栏里。这意味着SearchView的搜索界面使用了与应用完全一致的样式与主题。要使用操作视图,只需在菜单项标签中添加一个android:actionViewClass属性即可。

在菜单XML中指定操作视图,相当于告诉Android“不要在操作栏对此菜单项使用常规视图部件,请使用指定的视图类”。通常,这也意味着连带获得了其它不同的行为。一个典型的例子是:SearchView不会产生任何onOptionsItemSelected(…)回调方法。这反而带来了方便,因为这意味着可将这些回调方法预留给那些不支持操作视图的老设备使用。

 <item
        android:id="@+id/menu_item_search"
        android:actionViewClass="android.widget.SearchView"
        android:icon="@android:drawable/ic_menu_search"
        android:showAsAction="ifRoom"
        android:title="@string/search"/>

在发送搜索intent之前,SearchView还需要知道当前的搜索配置信息。

@SuppressLint("NewApi")
    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        super.onCreateOptionsMenu(menu, inflater);
        inflater.inflate(R.menu.fragment_photo_gallery, menu);
        /** 
         * SearchManager.getSearchableInfo(ComponentName)方法可查找manifest配置,打包相关信息并返回
         * SearchableInfo对象,然后再将SearchableInfo对象转发给SearchView实例即可。
         */
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            MenuItem menuItem = menu.findItem(R.id.menu_item_search);
            SearchView searchView = (SearchView) menuItem.getActionView();//获取菜单项的操作视图

            SearchManager searchManager = (SearchManager) getActivity()
                    .getSystemService(Context.SEARCH_SERVICE);
            ComponentName name = getActivity().getComponentName();
            SearchableInfo searchableInfo = searchManager
                    .getSearchableInfo(name);

            searchView.setSearchableInfo(searchableInfo);
        }
    }

代码地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值