文档章节

自定义SearchView的搜索提示

CrazyManDF
 CrazyManDF
发布于 2017/08/21 10:34
字数 1230
阅读 109
收藏 0

1. SearchRecentSuggestionsProvider

  首先要创建自己的SearchRecentSuggestionsProvider,用于保存和查询搜索记录。

1.1 创建SearchRecentSuggestionsProvider

  SearchRecentSuggestionsProvider基本实现了进行读写搜索历史所需的所有功能,只需继承它并定义ContentProvider的AUTHORITY和Mode。Mode必须包含 DATABASE_MODE_QUERIES ,可选包含 DATABASE_MODE_2LINES 来让历史记录具有两行内容。具体内容如下:

public class SimpleSearchSuggestionsProvider extends SearchRecentSuggestionsProvider {
	private static final String LOG_TAG = SimpleSearchSuggestionsProvider.class.getSimpleName();
 
	public final static String AUTHORITY = "com.nex3z.examples.customsearchsuggestionitem.SimpleSearchSuggestionsProvider";
	public final static int MODE = DATABASE_MODE_QUERIES;
 
	public SimpleSearchSuggestionsProvider() {
		setupSuggestions(AUTHORITY, MODE);
	}
}

  然后要在AndroidManifest.xml中声明这个ContentProvider:

<application
...
	<provider
		android:name=".SimpleSearchSuggestionsProvider"
		android:authorities="com.nex3z.examples.customsearchsuggestionitem.SimpleSearchSuggestionsProvider" />
...
</application>

1.2. 保存搜索记录

  有了SimpleSearchSuggestionsProvider,就可以使用SearchRecentSuggestions可以很方便地保存搜索记录:

SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
		SimpleSearchSuggestionsProvider.AUTHORITY, SimpleSearchSuggestionsProvider.MODE);
suggestions.saveRecentQuery(query, null);

这里 saveRecentQuery() 的第一个参数代表要保存的搜索记录,第二个参数为可选添加的内容(需要在SearchRecentSuggestionsProvider设置 DATABASE_MODE_2LINES )。

1.3. 查询搜索记录

  可以按照使用一般ContentProvider的方法来查询搜索记录。这里使用了SearchManager来辅助建立uri:

public Cursor getRecentSuggestions(String query, int limit) {
	Uri.Builder uriBuilder = new Uri.Builder()
			.scheme(ContentResolver.SCHEME_CONTENT)
			.authority(SimpleSearchSuggestionsProvider.AUTHORITY);
 
	uriBuilder.appendPath(SearchManager.SUGGEST_URI_PATH_QUERY);
 
	String selection = " ?";
	String[] selArgs = new String[] { query };
 
	if (limit > 0) {
		uriBuilder.appendQueryParameter(
				SearchManager.SUGGEST_PARAMETER_LIMIT, String.valueOf(limit));
	}
 
	Uri uri = uriBuilder.build();
 
	return getContentResolver().query(uri, null, selection, selArgs, null);
}

2. 创建Suggestion Item

2.1. Item布局

  接下来创建自定义的Suggestion Item,在res/layout下建立search_suggestion_item.xml,其中包含一个用于显示图标的ImageView和一个用于显示提示的TextView:

<LinearLayout
	android:orientation="horizontal"
	...>
 
	<ImageView
		android:id="@+id/iv_suggestion_item_icon"
		.../>
 
	<TextView
		android:id="@+id/tv_suggestion_item_title"
		.../>
 
</LinearLayout>

2.2. 创建Adapter

  Adapter把从ContentProvider中获取的提示数据填充到上面创建的Item里,这里的Adapter就是一个简单的CursorAdapter。前面使用SearchRecentSuggestions的 saveRecentQuery() 方法来保存历史记录,对应地,这里要从 SearchManager.SUGGEST_COLUMN_TEXT_1 获取所保存的搜索历史记录。

[@Override](https://my.oschina.net/u/1162528)
public void bindView(View view, Context context, Cursor cursor) {
	ViewHolder viewHolder = (ViewHolder) view.getTag();
	viewHolder.mTitle.setText(
			cursor.getString(cursor.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1)));
}

3. 创建Searchable Configuration

  Searchable Configuration用于配置搜索对话框的UI。在res/xml下建立searchable.xml,其中必须包含 label ,通常为app的名称,一般不可见。这里还添加了 hint ,用于在用户未输入搜索内容时,在搜索框显示提示。由于这里使用了自定义的adapter来显示搜索提示,这里并不需要添加 searchSuggestAuthority 。

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

4. 配置Searchable Activity

  Searchable Activity用来处理搜索,当用户提交搜索后,系统会启动对应的Activity,搜索内容通过带有 ACTION_SEARCH 的intent来传递。

4.1. 声明Searchable Activity

  这里以MainActivity做为Searchable Activity,首先要在AndroidManifest.xml中声明。

<application
...
	<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>
		<intent-filter>
			<action android:name="android.intent.action.SEARCH" />
		</intent-filter>
		<meta-data
			android:name="android.app.searchable"
			android:resource="@xml/searchable" />
	</activity>
 
...
</application>

首先要添加meta-data,指向上一步中创建的Searchable Configuration(searchable.xml)。然后还要注册 android.intent.action.SEARCH的intent-filter,用于接收用户提交搜索后由系统发出的intent。注意这里还设置了 launchMode 为 singleTop ,避免搜索时重复启动Activity。

4.2. 添加搜索菜单

  在res/menu/下添加menu_search.xml如下:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
	xmlns:app="http://schemas.android.com/apk/res-auto">
	<item android:id="@+id/action_search"
		android:title="@string/action_search"
		android:icon="@drawable/ic_search_24dp"
		app:showAsAction="collapseActionView|ifRoom"
		app:actionViewClass="android.support.v7.widget.SearchView" />
</menu>

搜索菜单以放大镜图标按钮的形式显示,注意这里指定 app:actionViewClass 为Support Library的SearchView。

4.3. 配置SearchView

  首先在onCreateOptionsMenu()找到搜索菜单对应的MenuItem:

@Override
public boolean onCreateOptionsMenu(Menu menu){
	getMenuInflater().inflate(R.menu.menu_search, menu);
	MenuItem searchItem = menu.findItem(R.id.action_search);
	...
}

  然后由searchItem获取SearchView,并通过SearchManager配置SearchableInfo,也就是之前的searchable.xml:

SearchManager searchManager =
		(SearchManager) getSystemService(Context.SEARCH_SERVICE);
final SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));

接下来把SearchSuggestionAdapter配置到searchView(注意SearchView的 setSuggestionsAdapter() 只支持CursorAdapter):

mSuggestionAdapter = new SearchSuggestionAdapter(this, null, 0);
searchView.setSuggestionsAdapter(mSuggestionAdapter);

当搜索框内容变化时,从ContentProvider查询对应的搜索记录,并传递给adapter:

searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
	@Override
	public boolean onQueryTextSubmit(String query) {
		return false;
	}
 
	@Override
	public boolean onQueryTextChange(String newText) {
		Cursor cursor = getRecentSuggestions(newText, 10);
		mSuggestionAdapter.swapCursor(cursor);
		return false;
	}
});

  当suggestion被选中时,把对应suggestion内容填充到搜索栏,并触发搜索:

searchView.setOnSuggestionListener(new SearchView.OnSuggestionListener() {
	@Override
	public boolean onSuggestionSelect(int position) {
		return false;
	}
 
	@Override
	public boolean onSuggestionClick(int position) {
		searchView.setQuery(mSuggestionAdapter.getSuggestionText(position), true);
		return true;
	}
});

这里 setQuery() 的第二个参数指示是否触发搜索,这里设为true,当用户点击搜索历史提示时,会立即搜索指定关键词。

4.4. 处理搜索

  使用自定义搜索提示时,处理搜索并没有什么不同,这里顺带一提。当用户提交搜索后,系统会启动对应的Searchable Activity,发送ACTION_SEARCH intent,其中带有名为 QUERY 的String extra保存了搜索内容。 首先在 onCreate() 中调用 handleIntent() 来处理 ACTION_SEARCH ,另外Activity设置了 launchMode 为 "singleTop" ,还需要在 onNewIntent() 中调用 handleIntent() 。

@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.activity_main);
 
	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);
		SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
				SimpleSearchSuggestionsProvider.AUTHORITY, SimpleSearchSuggestionsProvider.MODE);
		suggestions.saveRecentQuery(query, null);// 保存最近的数据
	}
}

5. 完整代码

https://github.com/nex3z/android-examples/tree/master/CustomSearchSuggestionItem

本文转载自:https://blog.nex3z.com/2016/04/07/%E8%87%AA%E5%AE%9A%E4%B9%89searchview%E7%9A%84%E6%90%9C%E7%B4%A2%E

CrazyManDF
粉丝 3
博文 81
码字总数 34160
作品 0
程序员
私信 提问
Android 搜索框 search dialog 和 search widget

分为search dialog和search widget 区别: A,search dialog是一个被系统控制的UI组件。但他被用户激活的时候,它总是出现在activity的上。 B,Android系统负责处理search dialog上所有的事件,...

CrazyManDF
2016/08/08
269
0
在做Android列表搜索?那我这里有几个不成熟小参考

一、列表数据搜索 对于常见的列表搜索,大概分两种,一种是在当前页面搜索,一种是跳页面搜索。 1、RecyclerView和listView等的列表搜索 2、搜索联系人 3、搜索应用名称 等等。 1、取自数据库...

阿敏其人
2016/10/21
0
0
android SearchView

SearchView一个为用户提供输入搜索查询和提交请求给搜索提供者的用户界面部件。显示查询建议或结果列表,如果有的话,运行用户选择一条查询建议或结果并启动与其相关的操作。 内部类   int...

amigos_wu
2012/06/11
2.4K
0
Material Design风格SearchView实现语音搜索功能《IT蓝豹》

Material Design风格SearchView实现语音搜索功能 Material Design风格SearchView实现语音搜索功能,弹出录音对话框效果也很漂亮。 但是这份代码支持在5.0以上的手机才能看到效果。 VoiceAct...

抉择很难
2015/10/13
131
0
我的网站搭建 (第十三天) 自定义全文搜索

关于全文搜索的部分,主要是利用了haystack,whoosh和jieba这三个包,而且必须安装,否则以下内容无效。详细的说法已经在之前Django框架的学习内容中总结过了:Django 框架15: 全文搜索 这次...

代码打碟手
2018/09/04
63
0

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周日乱弹 —— 我,小小编辑,食人族酋长

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @宇辰OSC :分享娃娃的单曲《飘洋过海来看你》: #今日歌曲推荐# 《飘洋过海来看你》- 娃娃 手机党少年们想听歌,请使劲儿戳(这里) @宇辰OSC...

小小编辑
51分钟前
114
7
spring cloud

一、从面试题入手 1.1、什么事微服务 1.2、微服务之间如何独立通讯的 1.3、springCloud和Dubbo有哪些区别 1.通信机制:DUbbo基于RPC远程过程调用;微服务cloud基于http restFUL API 1.4、spr...

榴莲黑芝麻糊
今天
2
0
Executor线程池原理与源码解读

线程池为线程生命周期的开销和资源不足问题提供了解决方 案。通过对多个任务重用线程,线程创建的开销被分摊到了多个任务上。 线程实现方式 Thread、Runnable、Callable //实现Runnable接口的...

小强的进阶之路
昨天
6
0
maven 环境隔离

解决问题 即 在 resource 文件夹下面 ,新增对应的资源配置文件夹,对应 开发,测试,生产的不同的配置内容 <resources> <resource> <directory>src/main/resources.${deplo......

之渊
昨天
8
0
详解箭头函数和普通函数的区别以及箭头函数的注意事项、不适用场景

箭头函数是ES6的API,相信很多人都知道,因为其语法上相对于普通函数更简洁,深受大家的喜爱。就是这种我们日常开发中一直在使用的API,大部分同学却对它的了解程度还是不够深... 普通函数和...

OBKoro1
昨天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部