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. JS开发打气球游戏

    JS开发打气球游戏 观视频<月薪4万的程序员有多强?半小时原生JS开发打气球游戏,征服现场数万人!> 清晨,日常打开B站,被首页此视频的标题所吸引,虽一看就是标题党,但还是没能抑制住好奇心 ...

  2. Windows下安装Tensorflow(python3.6):记录过程

    安装前的情况: 之前使用的都是python2.7,但是tensorflow不支持2.x版本,那只有基于在3.x版本进行安装了 前段时间,我安装VS2017的时候安装了python3.6于是想在此基础上 ...

  3. Spring框架学习——Spring的体系结构详解

    1.Spring简介 Spring是一个轻量级Java开发框架,最早有Rod Johnson创建,目的是为了解决企业级应用开发的业务逻辑层和其他各层的耦合问题.它是一个分层的JavaSE/JavaEE ...

  4. ARP协议详解之Gratuitous ARP(免费ARP)

    ARP协议详解之Gratuitous ARP(免费ARP) Gratuitous ARP(免费ARP) Gratuitous ARP也称为免费ARP,无故ARP.Gratuitous ARP不同于一般 ...

  5. 什么情况下,会用到fiddler或者charles?

    有的页面,比如设限制的html页面,比如原生页面,只能在手机APP里面查看,无法在电脑浏览器中打开查看,这时候,需要用fiddler抓包来查看返回数据,定位问题.

  6. 线上zk节点报org.apache.zookeeper.server.NIOServerCnxnFactory.run(NIOServerCnxnFactory.java:187) at java.lang.Thread.run(libgcj.so.10)

    线上zk做配置管理,最近突然发现两个节点一直在刷下边 java.nio.channels.CancelledKeyException    at gnu.java.nio.SelectionKeyIm ...

  7. Scanner和BufferedReader的区别和用法

    在命令行模式下要输入数据至程序中时,我们可以使用标准输入串对象System.in.但是,我们并不经常直接使用它,因为System.in提供的 read方法每次只能读取一个字节的数据,而我们平时所应用的 ...

  8. hdu 5652 India and China Origins(二分+bfs || 并查集)BestCoder Round #77 (div.2)

    题意: 给一个n*m的矩阵作为地图,0为通路,1为阻碍.只能向上下左右四个方向走.每一年会在一个通路上长出一个阻碍,求第几年最上面一行与最下面一行会被隔开. 输入: 首行一个整数t,表示共有t组数据. ...

  9. hadoop 视频教程2

    Hadoop大数据零基础实战培训教程 一,教程内容: 1,Hadoop2.0YARN深入浅出系列 2,Avro数据序列化系统 3,Chukwa集群监控系统 4,Flume日志收集系统 5,Greenp ...

  10. Linux shell 脚本小记2

    .从文件读取 while read line do echo "line=$line" done < file.txt .将字符串转换为数组,并进行遍历 str=" ...