searchView的语音搜索功能
Google的官方组件越来越丰富,功能也越来越多但是由于Google服务没有入华的原因导致一系列的服务不可用,今天就踩了Google语音的坑
我的效果图
前几天看到无聊看设计的时候看到了Google 官方的设计图
觉得还不错,真好我要做一版blog的Anndroid 端,于是就采用了这个非常常见的ToolBar的,我接触ToolBar也不是第一次了,对他的印象就是轻便好用,二话不说,先上代码(Java部分采用kotlin语言)
首先在activity的layout文件上将toolbar放入AppBarLayout
<android.support.design.widget.AppBarLayout android:layout_height="wrap_content"
android:layout_width="match_parent"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
app:title="首页"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
然后在res文件下的menu目录下(没有的话自己创建一个)新建menu.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:imeOptions="actionSearch"
android:title="@string/search"
app:actionViewClass="android.support.v7.widget.SearchView"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:title="@string/action_settings"
app:showAsAction="never" />
</menu>
最后重写Activity的onCreateOptionsMenu()方法
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.main, menu)
return true
}
来看看效果
然后就是语音按钮了,习惯性百度,但是却没有相关资料,只能去看看Google 官方文档了
https://developer.android.google.cn/guide/topics/search/search-dialog.html#SearchableConfiguration
我这这里找到了相关的说明
原来SearchView依赖一个叫Searchable类作为配置类,不过这个类是final修饰的不能够new 可以通过xml文件来写配置,总体来说分为以下几步
第一步
在res/xml/ 路径下新建一个searchable.xml 文件
内容
<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/search"
android:hint="请输入内容"
android:voiceSearchMode="showVoiceSearchButton|launchRecognizer"
>
</searchable>
其中 android:voiceSearchMode="showVoiceSearchButton|launchRecognizer" 这句话就是显示语音按钮,官网也给了解释
第二步
在manifests的activity加一个 action 和一个meta-data,将我们刚才创建的xml引入 具体如下
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="singleTop"
android:theme="@style/AppTheme.NoActionBar" >
<intent-filter>
<action android:name="android.intent.action.SEARCH"/>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="android.app.searchable"
android:resource="@xml/searchable"/>
</activity>
第三步
修改代码让SearchView 加载 searchable
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.main, menu)
val searchMenuItem = menu.findItem(R.id.action_search)
val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
val searchView = searchMenuItem.actionView as SearchView
val searchView = menu.findItem(R.id.action_search).actionView as SearchView
searchView.setSearchableInfo(searchManager.getSearchableInfo(componentName))
return true
}
大功告成,于是立马去运行下看看效果,然后并没卵用,语音按钮还是没出来,百思不得其解,还是老老实实去看看SearchView的源码吧,不懂原理始终是被人牵着走呀
Google的源码还是很规范的
......
final ImageView mSearchButton;
final ImageView mGoButton;
final ImageView mCloseButton;
final ImageView mVoiceButton;
......
顾名思义 mVoiceButton就是语音按钮
`
private boolean mVoiceButtonEnabled;
`
又发现个boolean参数,猜的没错的话这个就是控制语音按钮显示的吧,接着看源码,找到了这段
private void updateVoiceButton(boolean empty) {
int visibility = GONE;
if (mVoiceButtonEnabled && !isIconified() && empty) {
visibility = VISIBLE;
mGoButton.setVisibility(GONE);
}
mVoiceButton.setVisibility(visibility);
}
果然是这样的,不过voice不仅仅受限制于它,还有其他的参数限制,看到这里我突然想到,是不是我没安装Google搜索服务导致的,立马打开我的GooglePlay
安装了这货然后
语音图标就出来了,如果要完整的实现语音功能还是要在Activity解析Google语音返回回来的消息还是要在Activity里解析的,所以完整的第三步是这样的
### 完整的第三步
private lateinit var searchView: SearchView
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.main, menu)
val searchMenuItem = menu.findItem(R.id.action_search)
val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
searchView = searchMenuItem.actionView as SearchView
val searchView = menu.findItem(R.id.action_search).actionView as SearchView
searchView.setSearchableInfo(searchManager.getSearchableInfo(componentName))
return true
}
override fun onNewIntent(intent: Intent) {
setIntent(intent)
handleIntent(intent)
}
private fun handleIntent(intent: Intent) {
if (Intent.ACTION_SEARCH == intent.action) {
val query = intent.getStringExtra(SearchManager.QUERY)
searchView.setQuery(query,false)
searchView.setIconifiedByDefault(true)
}
}
注意!!
Activity 的启动模式要设置为singleTop 否则会无限次打开
终于知道为什么百度都找不到方案了,原来这货需要Google服务的支持,
所以忙活了半天也是瞎忙活,好在阿里云提供了免费的语音解析服务(好歹也是用的云栖社区,肯定要给阿里个面子),看来要手动造轮子了下周见,源码见附件,完整blog上线我会提供github地址