検索インターフェースを設定する

アプリ内に検索機能を提供するために、SearchView ウィジェットをアプリバーのアイテムとして使用することをおすすめします。アプリバーのすべてのアイテムと同様に、SearchView を常に表示するか、余裕があるときにのみ表示するかを定義できます。これを折りたたみ可能なアクションとして定義することもできます。折りたたみ可能なアクションでは、最初は SearchView をアイコンとして表示し、ユーザーがアイコンをタップするとアプリバー全体が検索フィールドとして表示されます。

SearchView をアプリバーに追加する

SearchView ウィジェットをアプリバーに追加するには、プロジェクト内に res/menu/options_menu.xml という名前のファイルを作成し、次のコードを追加します。このコードは、使用するアイコンやアイテムのタイトルなど、検索アイテムの作成方法を定義します。collapseActionView 属性を使用すると、SearchView を展開してアプリバー全体を占め、使用しないときは通常のアプリバー項目に折りたたむことができます。スマートフォン デバイスではアプリバーのスペースが限られているため、collapsibleActionView 属性を使用してユーザー エクスペリエンスを向上させることをおすすめします。

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/search"
        android:title="@string/search_title"
        android:icon="@drawable/ic_search"
        android:showAsAction="collapseActionView|ifRoom"
        android:actionViewClass="androidx.appcompat.widget.SearchView" />
</menu>

検索アイコンにアクセスしやすくするには、/res/drawable フォルダに ic_search.xml ファイルを作成し、そのファイルに次のコードを含めます。

<vector
    android:height="24dp"
    android:tint="#000000"
    android:viewportHeight="24"
    android:viewportWidth="24"
    android:width="24dp"
    xmlns:android="http://schemas.android.com/apk/res/android">
        <path android:fillColor="@android:color/white" android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
</vector>

SearchView をアプリバーに表示するには、アクティビティの onCreateOptionsMenu() メソッドで XML メニュー リソース res/menu/options_menu.xml をインフレートします。

Kotlin

override fun onCreateOptionsMenu(menu: Menu): Boolean {
    menuInflater.inflate(R.menu.options_menu, menu)

    return true
}

アプリを実行すると、次のような出力が生成されます。

アプリのトップバーに検索アイコンがある空の画面を示す画像
図 1. アプリのトップバー上の検索アイコン

SearchView はアプリのアプリバーに表示されますが、機能しません。検索アイコンをタップすると、次のように表示されます。

検索ビューの動作を示す画像
図 2. SearchView の動作

SearchView を機能させるには、SearchView の動作を定義する必要があります。

検索構成を作成する

検索構成SearchView の動作を指定し、res/xml/searchable.xml ファイルで定義されます。検索構成には、少なくとも、Android マニフェストの <application> 要素または <activity> 要素の android:label 属性と同じ値を持つ android:label 属性が含まれている必要があります。ただし、検索ボックスに何を入力するかをユーザーが把握できるように、android:hint 属性を追加することをおすすめします。

<?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" />

アプリのマニフェスト ファイルで、res/xml/searchable.xml ファイルを指す <meta-data> 要素を宣言します。SearchView を表示する <activity> で要素を宣言します。

<activity
android:name=".SearchResultsActivity"
android:exported="false"
android:label="@string/title_activity_search_results"
android:launchMode="singleTop"
android:theme="@style/Theme.AppCompat.Light">
    <intent-filter>
        <action android:name="android.intent.action.SEARCH" />
    </intent-filter>
    <meta-data
        android:name="android.app.searchable"
        android:resource="@xml/searchable" />
</activity>

作成する onCreateOptionsMenu() メソッドで setSearchableInfo(SearchableInfo) を呼び出して、検索構成を SearchView に関連付けます。

Kotlin

override fun onCreateOptionsMenu(menu: Menu): Boolean {
    menuInflater.inflate(R.menu.options_menu, menu)

    val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
    val searchView = menu.findItem(R.id.search).actionView as SearchView
    val component = ComponentName(this, SearchResultsActivity::class.java)
    val searchableInfo = searchManager.getSearchableInfo(component)
    searchView.setSearchableInfo(searchableInfo)
    return true
}

getSearchableInfo() を呼び出すと、検索構成 XML ファイルから作成された SearchableInfo オブジェクトを取得できます。検索設定が SearchView に正しく関連付けられ、ユーザーがクエリを送信すると、SearchViewACTION_SEARCH インテントでアクティビティを開始します。このインテントでフィルタして検索クエリを処理できるアクティビティが必要になります。

検索可能なアクティビティを作成する

検索可能なアクティビティは ACTION_SEARCH インテントをフィルタし、データセットでクエリを検索します。検索可能なアクティビティを作成するには、任意のアクティビティを宣言して、ACTION_SEARCH インテントをフィルタするようにします。

<activity android:name=".SearchResultsActivity" ... >
    ...
    <intent-filter>
        <action android:name="android.intent.action.SEARCH" />
    </intent-filter>
    ...
</activity>

検索可能なアクティビティでは、onCreate() メソッドで ACTION_SEARCH インテントを確認して処理します。

Kotlin

class SearchResultsActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_search_results)
        handleIntent(intent)
    }

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        handleIntent(intent)
    }

    private fun handleIntent(intent: Intent) {
        if (Intent.ACTION_SEARCH == intent.action) {
            val query = intent.getStringExtra(SearchManager.QUERY)
            Log.d("SEARCH", "Search query was: $query")
        }
    }
}

これで、SearchView がユーザーのクエリを受け入れ、ACTION_SEARCH インテントで検索可能なアクティビティを開始できるようになりました。

検索クエリを取得したら、ViewModel に渡すことができます。ここで、クエリをアーキテクチャの他のレイヤで使用して、表示する検索結果を取得します。