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

Compose の方法を試す
Jetpack Compose は、Android に推奨される UI ツールキットです。Compose で検索機能を追加する方法について学びます。

アプリで検索機能を提供するには、アプリバーの項目として 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 に渡すことができます。アーキテクチャの他のレイヤでこのクエリを使用して、表示する検索結果を取得できます。