Search Dialog是提供搜索的控件之一,还有一个是上次小例子给出的searchView,关于SearchView的东西后面会说到。本次先从Search Dialog说起,让大家慢慢理解android中搜索的控件的机制,逐渐引出搜索信息传递和搜索配置的知识,铺垫到最后再给大家说searchview的话,大家就能很容易理解。

一、Search Dialog 和 Search View

这两个其实都是一个搜索控件,区别不大,但多少还是有些小的差异的。

不同点:

A:search dialog是一个被系统控制的UI组件。但他被用户激活的时候,它“总是”出现在activity的上方,如图所示:
B:Android系统自己负责处理search dialog上所有的事件,当用户点击查询按钮,系统会把这个查询请求传输到我们自己定义的的searchable activity,这个searchable activity处理真正的查询。当用户在输入的时候,search dialog还能提供搜索建议。(这点下文会有提及)
C:而SearchView其实就是一个view,你自然可以把它放在你的布局的任何地方。(但一般我们还是将其放在屏幕的上方)
D:默认的,searchView和一个标准的EditText一样,不能做任何事情。但是你可以配置它,让android系统处理所有的按键事件,把查询请求传输给合适的activity,可以配置它让它像search dialog一样提供search suggestions(搜索建议)。
E:search widget在 Android 3.0或更高版本才可用. search dialog没有此项限制。(如果要在低版本使用,需要用support包中提供的控件)
 
二、搜索程序的构成
 
实现一个可以搜索的程序,主要需要以下几个部份:
(1),search dialog or search view的配置文件。
配置一个XML文件用于配置search dialog 或widget的设置。对于search dialog,该配置文件的名字一般约定为searchable.xml(推荐) 
(2)searchable Activity。
searchable activity用于接收搜索关键字,并进行数据搜索和显示搜索结果。
(3)搜索框 (search dialog 或search View)
    * search dialog
      默认的,search dialog是隐藏。当我们按下了SEARCH键或在程序中调用onSearchRequested(),它将出现在屏幕的上方.
    * search view 
  使用search widget的时候,你可以把该搜索条放在我们activity的任何地方。
 
 
三、编写SearchDialog的配置文件
 
3.1 配置搜索框
接着我们需要定义搜索框的配置文件,依据官方的建议,我选用了searchable作为xml文件的名字。
该文件一般约定为searchable.xml并位于res/xml/目录下。
searchable.xml必须以<searchable> element 作为根节点,且至少定义一个属性。
<?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"
android:icon="@drawable/kale"> </searchable>
  3.1.1 android:label
  android:label是唯一必须定义的属性。它指向一个字符串,它应该是应用程序的名字。所以我这里直接用了app_name。实际上该label也只有在search suggestions for Quick Search Box可用时才可见。
  3.1.2 android:hint
  android:hint属性不是必须,但是希望大家定义它。它是search box用户输入前输入框中的提示语。
<searchable> 还有其他的一些属性。如果不需要search suggestions 和voice search的话,大多数的属性是不需要的。未来可能有文章去专门介绍这个配置文件。
 
四、配置Activity
 
我的思路是一个activity用于给用户提供输入,用户点击搜索后跳转到另一个activity开始执行搜索。提供用户输入的Activity叫做MainActivity,真正执行搜索的Activity叫做SearchActivity。下面是它们在manifest中的定义:
        <activity
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="singleTop" >
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> <!-- enable the search dialog to send searches to SearchableActivity -->
<meta-data
android:name="android.app.default_searchable"
android:value="com.kale.searchdialogtest.SearchActivity" />
</activity> <activity
android:name="com.kale.searchdialogtest.SearchActivity"
android:launchMode="singleTop" >
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter> <meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>

为了方便解释,我们直接看主要代码:

MainActivity:

    <activity
android:name=".MainActivity"
android:launchMode="singleTop" >
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> <!-- enable the search dialog to send searches to SearchableActivity -->
<meta-data
android:name="android.app.default_searchable"
android:value="com.kale.searchdialogtest.SearchActivity" />
</activity>
这个代码中用了singleTop来设置activity,官方建议是用于搜索和展示信息的activity用singleTop定义,这里的mainActivity虽然仅仅是提供输入的,但为了后续的例子,我还是用了singleTop模式。然后就是设定它是启动时第一展示的activity。下面重点来了。
            <!-- enable the search dialog to send searches to SearchableActivity -->
<meta-data
android:name="android.app.default_searchable"
android:value="com.kale.searchdialogtest.SearchActivity" />
我们知道,当用户提交搜索结果的时候,系统就启动一个我们定义的searchable activity(就是这个例子中的SearchActivity) ,并把搜索关键字用一个aciton(名字为CTION_SEARCH的Intent传给你的searchable activity)。这样,在searchable activity就可以让Intent中通过extra的QUERY来提取搜索关键字,执行搜索并显示搜索结果。那么如何让系统知道提交搜索时,是启动哪个activity呢?就是通过上面这两行配置文件做的。
要求:
1. 必须包含“android:value”属性,该属性指明了searchable activity的类名,
2. 必须包括属性“android:name",且其值必须为 "android.app.default_searchable".
 
这样系统就知道用户在提交搜索结果(一般是按下输入法上的回车/搜索按钮)时,应该启动那个activity了。
 
SearchActivity
<activity
android:name="com.kale.searchdialogtest.SearchActivity"
android:launchMode="singleTop" >
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter> <meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>

依据建议,用于展示搜索结果的activity应该用singleTop模式,同时要强制写上如下内容。

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

如果对activity的隐式启动有所了解的话,我们一眼就看出为什么要这么定义了。在MainActivity中系统会在用户提交搜索时产生一个intent,并且给intent放入搜索词,而且还定义了一个action。系统这时就开始找哪个activity中定义了 <action android:name="android.intent.action.SEARCH" />,找到这个activity后就会自动启动我们的这个searchActivity。至于meta-data中的东西,其实就是一个search的配置信息。

 
 
五、编写这两个Activity中的代码
 
1. MainActivity
package com.kale.searchdialogtest;public class MainActivity extends ActionBarActivity {

    @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); Button btn = (Button) findViewById(R.id.show_dialog_button);
btn.setOnClickListener(new OnClickListener() { @Override
public void onClick(View v) {
onSearchRequested();
}
}); } }

很简单吧,通过onSearchRequested()我们就可以让activity中显示出一个search dialog,所以在某种意义上说,search dialog不用程序员进行过多干预。

 
扩展:
系统默认会将用户输入的信息传递到searchActivity中,在searchActivity中我们用过intent就可以得到这个输入信息了。但如果我们希望顺便传递另外一些信息呢?这时就需要重写onSearchRequested方法了。
package com.kale.searchdialogtest;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button; public class MainActivity extends ActionBarActivity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); Button btn = (Button) findViewById(R.id.show_dialog_button);
btn.setOnClickListener(new OnClickListener() { @Override
public void onClick(View v) {
onSearchRequested(); }
}); }
// 重写onSearchRequested方法
@Override
public boolean onSearchRequested() {
// 除了输入查询的值,还可额外绑定一些数据
Bundle appSearchData = new Bundle();
appSearchData.putString("KEY", "text"); startSearch(null, false, appSearchData, false);
// 必须返回true。否则绑定的数据作废
return true;
} }

我们在这里面放入了一个键值对,KEY-text。

 
2.SearchActivity
package com.kale.searchdialogtest;

import android.app.Activity;
import android.app.SearchManager;
import android.content.Intent;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast; /**
* @author:Jack Tony
* @description :真正执行搜索和结果展示的Activity 一旦用户在search dialog中执行search操作,
* 系统将启动SearchableActivity 并向其传送ACTION_SEARCH intent.
* @date :2015年1月15日
*
* 参考自:http://zhouyunan2010.iteye.com/blog/1134147
*/
public class SearchActivity extends Activity { protected void onCreate(android.os.Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.search_activity); // Get the intent, verify the action and get the query
Intent intent = getIntent();
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY); doMySearch(query);
} // 获得额外递送过来的值
Bundle appData = intent.getBundleExtra(SearchManager.APP_DATA);
if (appData != null) {
String testValue = appData.getString("KEY");
System.out.println("extra data = " + testValue);
} } private void doMySearch(String query) {
// TODO 自动生成的方法存根
TextView textView = (TextView) findViewById(R.id.search_result_textView);
textView.setText(query);
Toast.makeText(this, "do search", 0).show();
}
}

主要内容是从intent中获得数据,然后进行处理。这里仅仅获得了数据,没有进行真正的搜索。

 
 
六、通过一个activity进行搜索和展示
 
上面演示的是用两个activity,一个进行输入,一个进行处理,那么如果我想用一个activity又进行输入,又进行处理呢?其实也很简单,二合一即可。
manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.kale.searchdialogtest"
android:versionCode="1"
android:versionName="1.0" > <uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" /> <application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" > <activity
android:name=".MainActivity"
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> </application> </manifest>
主要代码:
     <activity
android:name=".MainActivity" > <intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter> <meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>
因为这个activity有处理搜索结果的能力,所以就必须定义
            <meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable" />
你可能会问,为什么不写
       <meta-data
android:name="android.app.default_searchable"
android:value="com.kale.searchdialogtest.MainActivity" />
因为这个activity自身就已经声明了自己有处理信息的能力,所以不用重复定义了。
 
MainActivity.java
package com.kale.searchdialogtest;

import android.app.SearchManager;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast; public class MainActivity extends ActionBarActivity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handleIntent(getIntent()); Button btn = (Button) findViewById(R.id.show_dialog_button);
btn.setOnClickListener(new OnClickListener() { @Override
public void onClick(View v) {
onSearchRequested();
}
});
} private void handleIntent(Intent intent) {
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
doMySearch(query);
}
} private void doMySearch(String query) {
// TODO 自动生成的方法存根
Toast.makeText(this, "do search " + query, 0).show();
} }
和之前的一样,开始搜索后会启动一个activity,只不过启动的还是当前的activity,而且当前栈中会有两个mainActivity,为了处理搜索信息,需要在activity的oncreate中捕获intent。但这样的效果多多少少会让用户感觉不爽,所以我们需要进行如下的改动。
 
扩展:
 
用singleTop来设计MainActivity
 
manifest.xml
 <activity
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="singleTop" >
<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>
这里用了单例模式就可以让activity不重复启动了,那么问题就来了。不重复启动的话,如何接收intent呢?下面来解决这个问题。
 
MainActivity.java
package com.kale.searchdialogtest;

import android.app.SearchManager;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast; /**
* @author:Jack Tony
* @description :
*
* 当系统调用onNewIntent(Intent)的时候,表示activity并不是新建的, 所以getIntent()返回的还是
* 在onCreate()中接受到的intent.
* 因此你必须在onNewIntent(Intent)调用setIntent(Intent)来
* (这样保存的intent才被更新,之后你可以同过getIntent()来取得它).
*
* @date :2015年1月15日
*/
public class MainActivity extends ActionBarActivity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); Button btn = (Button) findViewById(R.id.show_dialog_button);
btn.setOnClickListener(new OnClickListener() { @Override
public void onClick(View v) {
onSearchRequested();
}
}); } @Override
protected void onNewIntent(Intent intent) {
setIntent(intent);
handleIntent(intent);
}
private void handleIntent(Intent intent) {
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
doMySearch(query);
}
} private void doMySearch(String query) {
// TODO 自动生成的方法存根
Toast.makeText(this, "do search " + query, 0).show();
} }
我通过onNewIntent让activity更新下intent,这样就可以接收到自己传给自己的数据了。当系统调用onNewIntent(Intent)的时候,表示activity并不是新建的, 所以getIntent()返回的还是onCreate()中接受到的intent. 因此你必须在onNewIntent(Intent)调用setIntent(Intent)来 (这样保存的intent才被更新,之后你可以同过getIntent()来取得它)
 
 
 
 
参考自:
http://blog.csdn.net/hudashi/article/details/7052815
http://blog.csdn.net/hudashi/article/details/7052824
http://blog.csdn.net/hudashi/article/details/7052831
http://blog.csdn.net/hudashi/article/details/7052840
 

详细解读Android中的搜索框(二)—— Search Dialog的更多相关文章

  1. 详细解读Android中的搜索框—— SearchView

    以前总是自己写的 今天看看别人做的 本篇讲的是如何用searchView实现搜索框,其实原理和之前的没啥差别,也算是个复习吧. 一.Manifest.xml 这里我用一个activity进行信息的输入 ...

  2. 详细解读Android中的搜索框(三)—— SearchView

    本篇讲的是如何用searchView实现搜索框,其实原理和之前的没啥差别,也算是个复习吧. 一.Manifest.xml 这里我用一个activity进行信息的输入和展示,配置方式还是老样子,写一个输 ...

  3. 详细解读Android中的搜索框(一)—— 简单小例子

    这次开的是一个讲解SearchView的栏目,第一篇主要是给一个小例子,让大家对这个搜索视图有一个了解,之后再分布细化来说. 目标: 我们先来定个目标,我们通过搜索框来输入要搜索的联系人名字,输入的时 ...

  4. 详细解读Android中的搜索框(四)—— Searchable配置文件

    <?xml version="1.0" encoding="utf-8"?> <searchable xmlns:android=" ...

  5. WPF实用指南一:在WPF窗体的边框中添加搜索框和按钮

    原文:WPF实用指南一:在WPF窗体的边框中添加搜索框和按钮 在边框中加入一些元素,在应用程序的界面设计中,已经开始流行起来.特别是在浏览器(Crome,IE,Firefox,Opera)中都有应用. ...

  6. extjs在窗体中添加搜索框

    在extjs中添加搜索框,搜索框代码如下: this.searchField = new Ext.ux.form.SearchField({            store : this.store ...

  7. Android 依据EditText搜索框ListView动态显示数据

    依据EditText搜索框ListView动态显示数据是依据需求来的,认为这之中涉及的东西可能比較的有意思,所以动手来写一写.希望对大家有点帮助. 首先.我们来分析下整个过程: 1.建立一个layou ...

  8. Android 根据EditText搜索框ListView动态显示数据

    根据EditText搜索框ListView动态显示数据是根据需求来的,觉得这之中涉及的东西可能比较的有意思,所以动手来写一写,希望对大家有点帮助. 首先,我们来分析下整个过程: 1.建立一个layou ...

  9. Win7系统右上角没有搜索怎么办?Win7找回资源管理器中的搜索框

    最近有win7系统用户发现打开资源管理器,文件夹等右上角没有搜索框,这让人十分不方便无法进行搜索,那么如何找回呢?下面小编就分享一下方法给大家.推荐 最好用的Win7系统下载 操作步骤: 1.打开Wi ...

随机推荐

  1. 自主搭建CNN训练时遇到的问题

    1.训练太慢 用nimibatch代替fullbatch https://www.cnblogs.com/guoyaohua/p/8724433.html 2.过拟合 最直接的解决过拟合问题的办法是增 ...

  2. 001.FTP简介及相关文件

    一 FTP简介 FTP(File Transfer Protocol)文件传输协议,用于Internet上控制文件的双向传输. 下载:远程主机拷贝文件至本地: 上传:本地主机拷贝文件至远程. 二 FT ...

  3. 反射调用 java bean的set和get方法

    一.使用java.beans.PropertyDescriptor import java.beans.IntrospectionException; import java.beans.Proper ...

  4. 多线程学习笔记八之线程池ThreadPoolExecutor实现分析

    目录 简介 继承结构 实现分析 ThreadPoolExecutor类属性 线程池状态 构造方法 execute(Runnable command) addWorker(Runnable firstT ...

  5. Plant Simulation常用命令

    Plant Simulation 是面向对象的三维离散事件仿真软件,使您能够快速.直观地构建逼真的物流模型. 您还可以使用高级统计工具执行复杂的生产分析.以下介绍该软件的一些常用命令. 1. clea ...

  6. apache2.4配置https

    1.获取证书 1.1 openssl生成SSL证书(自行百度) 1.2 腾讯云,阿里云,百度云等等都有提供免费的SSL证书 2.证书安装 编辑Apache根目录下 conf/httpd.conf 文件 ...

  7. Xtreme8.0 - Magic Square 水题

    Xtreme8.0 - Magic Square 题目连接: https://www.hackerrank.com/contests/ieeextreme-challenges/challenges/ ...

  8. Springboot 线程池配置

    最近的项目里要手动维护线程池,然后看到一起开发的小伙伴直接用Java了,我坚信Springboot不可能没这功能,于是查了些资料,果然有,这里给一下. 首先我们都知道@Async标签能让方法异步执行, ...

  9. HDU 4772 Zhuge Liang's Password (2013杭州1003题,水题)

    Zhuge Liang's Password Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/O ...

  10. Calculate CRC32 as in STM32 hardware (EWARM v.5.50 and later)

    http://supp.iar.com/Support/?note=64424&from=note+11927 BackgroundThe STM32 devices from ST Micr ...