Android SearchView + Toolbar 的语音搜索功能

searchView的语音搜索功能

Google的官方组件越来越丰富,功能也越来越多但是由于Google服务没有入华的原因导致一系列的服务不可用,今天就踩了Google语音的坑

我的效果图

giphy_1_

前几天看到无聊看设计的时候看到了Google 官方的设计图

image
image

觉得还不错,真好我要做一版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
    }

来看看效果

200w_d

然后就是语音按钮了,习惯性百度,但是却没有相关资料,只能去看看Google 官方文档了

https://developer.android.google.cn/guide/topics/search/search-dialog.html#SearchableConfiguration
我这这里找到了相关的说明
原来SearchView依赖一个叫Searchable类作为配置类,不过这个类是final修饰的不能够new 可以通过xml文件来写配置,总体来说分为以下几步

第一步

在res/xml/ 路径下新建一个searchable.xml 文件
image
内容

<?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" 这句话就是显示语音按钮,官网也给了解释
image

第二步

在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
WechatIMG157_jpeg
安装了这货然后
语音图标就出来了,如果要完整的实现语音功能还是要在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地址

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值