アクション ビューとアクション プロバイダの使用

v7 appcompat サポート ライブラリ Toolbar には、ユーザーがアプリを操作するためのさまざまな方法が用意されています。前のレッスンでは、アクション(ボタンまたはメニュー項目)を定義する方法について説明しました。このレッスンでは、2 つの汎用コンポーネントを追加する方法について説明します。

  • アクション ビューは、アプリバー内に豊富な機能を提供するアクションです。たとえば検索アクション ビューを使用すると、ユーザーはアクティビティまたはフラグメントを変更することなく、アプリバーに検索テキストを入力できます。
  • アクション プロバイダは、独自のカスタマイズされたレイアウトを持つアクションです。 アクションは、最初はボタンまたはメニュー項目として表示されますが、ユーザーがアクションをクリックすると、定義したい方法でアクション プロバイダがアクションの動作を制御します。たとえばアクション プロバイダは、メニューを表示することでクリックに対応する場合があります。

Android サポート ライブラリには、特殊なアクション ビューとアクション プロバイダ ウィジェットがいくつか用意されています。たとえば、SearchView ウィジェットは検索クエリを入力するためのアクション ビューを実装し、ShareActionProvider ウィジェットは他のアプリと情報を共有するためのアクション プロバイダを実装します。独自のアクション ビューとアクション プロバイダを定義することもできます。

アクション ビューの追加

アクション ビューを追加するには、アクション ボタンの追加で説明しているように、ツールバーのメニュー リソースに<item> 要素を作成します。次の 2 つの属性のいずれかを <item> 要素に追加します。

  • actionViewClass: アクションを実装するウィジェットのクラス。
  • actionLayout: アクションのコンポーネントを記述するレイアウト リソース。

showAsAction 属性を "ifRoom|collapseActionView" または "never|collapseActionView" のいずれかに設定します。collapseActionView フラグは、ユーザーがウィジェットを操作していないときにウィジェットを表示する方法を示します。ウィジェットがアプリバーにある場合、アプリはウィジェットをアイコンとして表示する必要があります。ウィジェットがオーバーフロー メニューにある場合、アプリはウィジェットをメニュー項目として表示する必要があります。ユーザーがアクション ビューを操作すると、アプリバーいっぱいに展開されます。

たとえば、次のコードは SearchView ウィジェットをアプリバーに追加します。

    <item android:id="@+id/action_search"
         android:title="@string/action_search"
         android:icon="@drawable/ic_search"
         app:showAsAction="ifRoom|collapseActionView"
         app:actionViewClass="android.support.v7.widget.SearchView" />
    

ユーザーがウィジェットを操作していない場合、アプリは android:icon で指定されたアイコンとしてウィジェットを表示します。(アプリバーに十分なスペースがない場合、アプリはオーバーフロー メニューにアクションを追加します。)ユーザーがアイコンまたはメニュー項目をタップすると、ウィジェットがツールバーいっぱいに展開され、ユーザーが操作できるようになります。

図 1. ユーザーがアクション ビューのアイコンをクリックすると、ビューの UI がツールバーいっぱいに表示されます。

アクションを構成する必要がある場合は、アクティビティの onCreateOptionsMenu() コールバックで構成します。getActionView() メソッドを呼び出すことで、アクション ビューのオブジェクト参照を取得できます。たとえば次のコードは、前のコード例で定義した SearchView ウィジェットのオブジェクト参照を取得します。

Kotlin

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

        val searchItem = menu?.findItem(R.id.action_search)
        val searchView = searchItem?.actionView as SearchView

        // Configure the search info and add any event listeners...

        return super.onCreateOptionsMenu(menu)
    }
    

Java

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main_activity_actions, menu);

        MenuItem searchItem = menu.findItem(R.id.action_search);
        SearchView searchView =
                (SearchView) searchItem.getActionView();

        // Configure the search info and add any event listeners...

        return super.onCreateOptionsMenu(menu);
    }
    

アクション ビューの展開への対応

アクションの <item> 要素に collapseActionView フラグがある場合、ユーザーがアクション ビューを操作するまで、アプリはアクション ビューをアイコンとして表示します。ユーザーがアイコンをクリックすると、onOptionsItemSelected() の組み込みハンドラがアクション ビューを展開します。アクティビティ サブクラスが onOptionsItemSelected() メソッドをオーバーライドする場合、オーバーライド メソッドは super.onOptionsItemSelected() を呼び出して、スーパークラスがアクション ビューを展開できるようにする必要があります。

アクションが展開されたときまたは折りたたまれたときに何かを行う場合は、MenuItem.OnActionExpandListener を実装するクラスを定義し、そのクラスのメンバーを setOnActionExpandListener() に渡せます。たとえば、アクション ビューが展開されているか折りたたまれているかに基づいて、アクティビティを更新できます。次のスニペットは、リスナーを定義して渡す方法を示しています。

Kotlin

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.options, menu)
        // ...

        // Define the listener
        val expandListener = object : MenuItem.OnActionExpandListener {
            override fun onMenuItemActionCollapse(item: MenuItem): Boolean {
                // Do something when action item collapses
                return true // Return true to collapse action view
            }

            override fun onMenuItemActionExpand(item: MenuItem): Boolean {
                // Do something when expanded
                return true // Return true to expand action view
            }
        }

        // Get the MenuItem for the action item
        val actionMenuItem = menu?.findItem(R.id.myActionItem)

        // Assign the listener to that action item
        actionMenuItem?.setOnActionExpandListener(expandListener)

        // Any other things you have to do when creating the options menu...

        return true
    }
    

Java

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.options, menu);
        // ...

        // Define the listener
        OnActionExpandListener expandListener = new OnActionExpandListener() {
            @Override
            public boolean onMenuItemActionCollapse(MenuItem item) {
                // Do something when action item collapses
                return true;  // Return true to collapse action view
            }

            @Override
            public boolean onMenuItemActionExpand(MenuItem item) {
                // Do something when expanded
                return true;  // Return true to expand action view
            }
        };

        // Get the MenuItem for the action item
        MenuItem actionMenuItem = menu.findItem(R.id.myActionItem);

        // Assign the listener to that action item
        MenuItemCompat.setOnActionExpandListener(actionMenuItem, expandListener);

        // Any other things you have to do when creating the options menu...

        return true;
    }
    

アクション プロバイダの追加

アクション プロバイダを宣言するには、アクション ボタンの追加で説明しているように、ツールバーのメニュー リソースに <item> 要素を作成します。actionProviderClass 属性を追加し、アクション プロバイダ クラスの完全修飾クラス名に設定します。

たとえば次のコードは、アプリが他のアプリとデータを共有できるようにする、サポート ライブラリで定義されているウィジェットである ShareActionProvider を宣言しています。

    <item android:id="@+id/action_share"
        android:title="@string/share"
        app:showAsAction="ifRoom"
        app:actionProviderClass="android.support.v7.widget.ShareActionProvider"/>
    

この場合、ShareActionProvider が独自のグラフィックを提供するため、ウィジェットのアイコンを宣言する必要はありません。カスタム アクションを使用している場合は、アイコンを宣言します。

カスタム アクション プロバイダの作成については、ActionProvider のリファレンスをご覧ください。ShareActionProvider の構成については、そのクラスのリファレンスをご覧ください。