Android 浮动搜索框 searchable 使用

    |     2016年2月26日   |   Android UI界面   |     0 条评论   |    1456

Android 给搜索提供了统一接口:search dialog 和 search widget。本文只讲 search dialog——它只能出现在 Activity 窗口上方。下面以点击 EditText 启动搜索框为例。

效果如下:

search1


一、searchable.xml

新建 searchable.xml,放在 res/xml,配置搜索框属性:

<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="@string/app_name"
    android:hint="@string/search_hint"/>
  • android:label 是唯一必须项,指向应用名。实际上只有在 Quick Search Box 的 search suggestions 可用时才看得见
  • android:hint 不是必须,但建议总是写上,是输入前的提示语

其它属性见官方文档:

<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="string resource"
    android:hint="string resource"
    android:searchMode=["queryRewriteFromData" | "queryRewriteFromText"]
    android:searchButtonText="string resource"
    android:inputType="inputType"
    android:imeOptions="imeOptions"
    android:searchSuggestAuthority="string"
    android:searchSuggestPath="string"
    android:searchSuggestSelection="string"
    android:searchSuggestIntentAction="string"
    android:searchSuggestIntentData="string"
    android:searchSuggestThreshold="int"
    android:includeInGlobalSearch=["true" | "false"]
    android:searchSettingsDescription="string resource"
    android:queryAfterZeroResults=["true" | "false"]
    android:voiceSearchMode=["showVoiceSearchButton" | "launchWebSearch" | "launchRecognizer"]
    android:voiceLanguageModel=["free-form" | "web_search"]
    android:voicePromptText="string resource"
    android:voiceLanguage="string"
    android:voiceMaxResults="int"
    >
    <actionkey
        android:keycode="KEYCODE"
        android:queryActionMsg="string"
        android:suggestActionMsg="string"
        android:suggestActionMsgColumn="string" >
</searchable>

二、Manifest 声明 Searchable Activity

搜索结果 Activity 可以是当前页,也可以单独一个。这里直接用当前 SearchActivity:

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <meta-data
        android:name="android.app.default_searchable"
        android:value=".SearchActivity"/>

    <activity android:name=".SearchActivity">
        <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>

activity 内 meta-data 的 android:name 必须是 android.app.searchable,android:resource 指向 res/xml/searchable.xml。


三、启动 search dialog

Activity 里调 onSearchRequested():

@Override
public void onClick(View v) {
    switch (v.getId()){
        case R.id.search_edit:
            onSearchRequested();
            break;
    }
}

搜索前要做别的事,重写 onSearchRequested:

@Override
public boolean onSearchRequested() {
    //这个方法中干你想干的事
    doSometingOther();
    return super.onSearchRequested();
}

需要带参数时:

public boolean onSearchRequested() {
    Log.i(TAG,"onSearchRequested------------========");
    Bundle appData = new Bundle();
    appData.putString("key", "your info");
    startSearch(null, true, appData, false);
    return true;
}

四、取出搜索关键字

关键字:String query = intent.getStringExtra(SearchManager.QUERY);。取之前先判断 action 是否为 android.intent.action.SEARCH:

Intent intent = getIntent();
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
    String query = intent.getStringExtra(SearchManager.QUERY);
}

五、结果在当前页处理:singleTop + onNewIntent

结果可以单独一个类,也可以在当前搜索框所在类处理。若在当前类处理,要设 singleTop,避免再创建 Activity。这时 onCreate 不会再走;若只在 onResume 里 getIntent(),拿到的还是旧 Intent,action 不是 SEARCH——搜索后 Intent 已经变了,Activity 里缓存的还是原来那个。正确做法:重写 onNewIntent,setIntent(intent) 更新后再处理。原文 handleIntent 误用了 getIntent() 而不是参数 intent,这里按参数修正:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_search_dialog_layout);
    mSearchEdit = (EditText) findViewById(R.id.search_edit);
    mContentTxt = (TextView) findViewById(R.id.search_content_txt);
    mSearchEdit.setOnClickListener(this);
    handleIntent(getIntent());
}

/** 重复刷新当前 Activity 时执行 */
@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);
    }
}

/** 处理搜索结果 */
public void doMySearch(String query){
    mContentTxt.setText(query);
}

六、记录搜索历史

查完希望留下关键字,用 SearchRecentSuggestionsProvider。先建 Provider:

public class SearchSuggestionProvider extends SearchRecentSuggestionsProvider {

    final static String AUTHORITY = "com.debby.googlemap.SuggestionProvider";
    final static int MODE = DATABASE_MODE_QUERIES;

    public SearchSuggestionProvider() {
        super();
        setupSuggestions(AUTHORITY, MODE);
    }
}

Manifest 里 authorities 必须和 Provider 一致:

<provider android:name="com.debby.googlemap.SearchSuggestionProvider"
    android:authorities="com.debby.googlemap.SuggestionProvider" />

Activity 里保存:

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

下次搜索就能看到历史。


七、清空历史

重写 Provider 的 query,在 Cursor 末尾加一条「清空历史记录」:

@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder, CancellationSignal cancellationSignal) {
    String[] items = null;
    Cursor cursor = super.query(uri, projection, selection, selectionArgs, sortOrder);
    int arrayLength = cursor.getCount();
    if (arrayLength != 0) {
        items = new String[arrayLength + 1];
        cursor.moveToFirst();
        int i = 0;
        for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
            int number = cursor.getColumnIndex("suggest_intent_query");
            items[i] = cursor.getString(number);
            i++;
        }
        items[i] = "清空历史记录";
    } else {
        return null;
    }

    String[] columns = new String[]{"suggest_format", "suggest_text_1", "suggest_intent_query", "_id"};
    MatrixCursor stringCursor = new MatrixCursor(columns);
    String row[] = new String[4];
    int i = 0;
    for (CharSequence item : items) {
        row[0] = "" + 0;
        row[1] = item.toString();
        row[2] = item.toString();
        row[3] = "" + (++i);
        stringCursor.addRow(row);
    }
    return stringCursor;
}

search4

步骤 关键点
searchable.xml label 必填,hint 建议填
Manifest SEARCH action + android.app.searchable 指向 xml
启动 onSearchRequested / startSearch 可带 Bundle
取关键字 ACTION_SEARCH + SearchManager.QUERY
当前页出结果 singleTop + onNewIntent + setIntent
历史 SearchRecentSuggestionsProvider 保存/清空

一句话总结:search dialog 靠 searchable.xml + Manifest;当前页出结果必须 singleTop 并在 onNewIntent 里换 Intent。

转载请注明来源:Android 浮动搜索框 searchable 使用
本文链接地址:https://ai.zhousir.top/?p=1328
回复 取消