如有错漏请不吝拍砖指正,转载请注明出处,非常感谢
我个人感觉从某种意义上讲,android用户体验的核心理念之一就是“无处不搜索”,
甚至包括chrome,都是此理念的最佳实践之一
因此android也提供了非常强大的自定义搜索开发的支持。
本文通过一个简单的示例程序,简单介绍自定义搜索实现的步骤,
实际上自定义搜索的功能远远强于本文所述。
SDK提供的 ApiDemos 例子程序中的 SearchInvoke.java 同样实现了自定义搜索,
本文可以看做是对其实现方法的分步骤讲解。
1.示例程序想达到的目的
我们编写这样一个自定义搜索,当用户发起搜索请求时,显示如下的自定义搜索界面:
点击搜索后,所有搜索请求将被我们的自定义搜索截获。
并显示在一个我们自定义的Activity中。例如我们搜索“Fxxk gfw !”, 会显示如下的界面活动:
这是一个toast风格的layout,会显示一个我们自定义的图标,然后显示被搜索的内容。
2.创建一个android工程
要想达到上述功能,首先我们创建一个android默认工程。
Activity起名为MySearchTester,作为自定义搜索的调用者。
这时按下搜索键,出现的是全局搜索界面,
注意全局搜索界面和第一步中的自定义搜索界面是有不同之处的。
然后我们修改 AndroidManifest.xml 中的 application 的 icon 属性为
android:icon="@android:drawable/star_big_on" 备用。
应用图标会作为自定义搜索界面的左侧图标显示出来,这里我们用了系统内置图标 star_big_on,
其最终效果就是第一步中自定义搜索界面里面那个黄色星星 :)
3.编写searchable.xml
要想达到上述功能,首先我们需要编写一个 searchable.xml 文件
这个文件非常重要,用来实现我们自定义搜索的各种参数。
在工程的res目录下新建目录xml,然后再xml目录下新建文件 searchable.xml。
必选的参数是用于标识的 label 属性,可以简单的定义为和应用同名,
其他参数都可选,不过一般建议使用hint参数定义搜索提示,
因此一个最简化的 searchable.xml 定义如下:
- <?xml version="1.0" encoding="utf-8"?>
- <searchable xmlns:android="http://schemas.android.com/apk/res/android"
- android:label="@string/search_name" android:hint="@string/search_hint"></searchable>
这里引用了两个字符串,其中 hint 提示将出现在我们自定义的搜索界面中。
4.编写搜索实现类的Activity
首先我们编写一个layout文件命名为 my_search.xml,内容如下:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:background="@android:drawable/toast_frame"
- >
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@android:drawable/stat_notify_chat"
- />
- <TextView
- android:id="@+id/message"
- android:layout_gravity="center_vertical"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingLeft="6dip"
- />
- </LinearLayout>
我们定义了一个LinearLayout,使用了一个toast frame作为background,
然后LinearLayout由两部分组成,
首先是一个图标,为了方便我直接调用了系统内置图标
然后是一个TextView,用来显示搜索内容
之后开始编写代码,新建一个类继承自Activity ,起名为 MySearchImpl,
重写 onCreate 方法,载入我们自定义的layout。
由于发生搜索时,系统的搜索框架会自动把搜索事件送入我们定义好的自定义搜索实现类中,
因此我们还需要在onCreate里面获取系统发送给我们的事件。
如果经过判断的确是搜索框架送来的事件,则取出搜索框架装配在事件上的搜索内容,
然后显示在我们定义的TextView中。代码如下:
- package com.silenceburn;
- import android.app.Activity;
- import android.app.SearchManager;
- import android.content.Intent;
- import android.os.Bundle;
- import android.widget.TextView;
- public class MySearchImpl extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- // TODO Auto-generated method stub
- super.onCreate(savedInstanceState);
- setContentView(R.layout.my_search);
- Intent intent = getIntent();
- if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
- String query = intent.getStringExtra(SearchManager.QUERY);
- TextView v = (TextView)this.findViewById(R.id.message);
- v.setText(query);
- }
- }
- }
注意代码本身除了处理搜索内容,其他地方并没有显式的和搜索框架及searchable.xml发生关系,
这些配置在是在下一步的AndroidManifest.xml配置中实现的。
5.注册自定义搜索的实现类
编写好实现类后,我们需要把实现类注册到 AndroidManifest.xml 中。
首先我们需要过滤事件,处理 android.intent.action.SEARCH 动作。
其次我们需要使用 meta-data 把实现类和 searchable.xml 配置文件关联起来。
编写好的实现类Activity注册的代码片段如下:
- <activity android:name=".MySearchImpl" android:label="@string/search_name">
- <intent-filter>
- <action android:name="android.intent.action.SEARCH" />
- </intent-filter>
- <meta-data
- android:name="android.app.searchable"
- android:resource="@xml/searchable"
- ></meta-data>
- </activity>
6. 将搜索调用者和自定义搜索实现关联起来
最后我们需要将我们的自定义搜索实现,和真正的搜索调用者关联起来,
我们把第二步生成默认工程时产生的类作为搜索调用者,为其关联自定义搜索实现。
关联同样是通过设置 meta-data 实现的。 编写好的 AndroidManifest.xml 如下所示:
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.silenceburn"
- android:versionCode="1"
- android:versionName="1.0">
- <application android:icon="@android:drawable/star_big_on" android:label="@string/app_name">
- <activity android:name=".MySearchTester"
- android:label="@string/app_name">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- <meta-data
- android:name="android.app.default_searchable"
- android:value=".MySearchImpl"
- ></meta-data>
- </activity>
- <activity android:name=".MySearchImpl" android:label="@string/search_name">
- <intent-filter>
- <action android:name="android.intent.action.SEARCH" />
- </intent-filter>
- <meta-data
- android:name="android.app.searchable"
- android:resource="@xml/searchable"
- ></meta-data>
- </activity>
至此示例程序编写完成,运行 MySearchTester ,点击搜索按钮呼出搜索界面,
会发现搜索界面已经变成自定义的搜索界面了。输入任意内容点击搜索,将送入我们自定义的搜索实现类中进行显示。
总结
我们可以注意到一个很有意思的地方,就是对于搜索调用者而言,
只需要在配置文件中指定自定义搜索, 代码中一行也没有涉及!
搜索调用者和自定义搜索实现之间,实现了非常好的解耦。
而自定义搜索的实现类和自定义搜索的配置之间,也是完全解耦的。
实现类中专注于如何处理搜索请求。searchable.xml则专注于配置自定义搜索的行为模式和各种配置参数。
这种良好的解耦,为设计提供了极大的便利。
再次强调本文只是自定义搜索的简单实现,自定义搜索还具备极其强大的搜索建议功能。
感兴趣的兄弟姐妹可查阅相关文档资料,有机会的时候我也会写写。
此外 searchable.xml 中的配置参数可查阅API文档 /sdk/api/guide/topics/search/searchable-config.html