Wear のロータリー入力

一部の Wear OS デバイスはロータリー入力(回転サイドボタン(RSB)など)をサポートしています。ユーザーがボタンを回すと、アプリの現在のビューが上または下にスクロールします。

アプリで ScrollViewListViewHorizontalScrollViewWearableRecyclerView のいずれかを使用している場合、アプリのビューはデフォルトでロータリー入力をサポートします。これら以外のカスタムビューを使用している場合や、ロータリー入力イベントを手動で処理する必要がある場合は、カスタムのロータリー入力スクロールを追加するをご覧ください。

以下の関連リソースもご覧ください。

フォーカスに関するおすすめの方法

ロータリー入力イベントに応答するには、スクロール ビューがフォーカスされている必要があります。ほとんどの場合、これは自動的に行われます。アクティビティを作成するとすぐに、スクロール ビューがフォーカスされます。ただし、以下のような状況では、アプリのビューのフォーカスを手動で処理する必要があります。

  • Activity.onCreate() の後にスクロール可能なビューがアタッチされる場合(UI を構築する前にネットワーク リクエストが終了するのを待機する場合など)、ビューがアタッチされた後に requestFocus を呼び出す必要があります。
  • スクロール可能なビューが最初に INVISIBLE または GONE に設定されている場合、VISIBLE に設定するときに requestFocus を呼び出す必要があります。
  • アクティビティにスクロール可能なビューが複数含まれている場合(ネストされたスクロールを使用している場合など)、1 つのビューにフォーカスする必要があります(通常は <requestFocus /> タグを使用)。現在、RSB のスクロールでは、ネストされたスクロールはサポートされていません。
  • ユーザーが操作したときにフォーカスを奪うビューが UI に含まれている場合(まれなケースですが、最もよく見られるのは InputText です)、スクロール可能なビューがフォーカスを失ったときにフォーカスを取り戻すなんらかの方法をユーザーに提供する必要があります。通常は、スクロール可能なビューのタップをリッスンし、タップされた場合に requestFocus を呼び出すことで、フォーカスを取り戻すことができます。

カスタムのロータリー入力スクロールを追加する

スクロール可能なビューがロータリー入力スクロールを標準でサポートしていない場合、または、ロータリー入力イベント(拡大 / 縮小、ダイヤルを回すなど)に対してスクロール以外の動作を行う必要がある場合は、ウェアラブル サポート ライブラリRotaryEncoder メソッドを使用できます。

次のコード スニペットは、RotaryEncoder を使用してカスタムのスクロールをアプリのビューに追加する方法を示しています。

Kotlin

    myView.setOnGenericMotionListener(View.OnGenericMotionListener { v, ev ->
        if (ev.action == MotionEvent.ACTION_SCROLL && RotaryEncoder.isFromRotaryEncoder(ev)) {
            // Don't forget the negation here
            val delta = -RotaryEncoder.getRotaryAxisValue(ev) *
                    RotaryEncoder.getScaledScrollFactor(context)

            // Swap these axes if you want to do horizontal scrolling instead
            v.scrollBy(0, Math.round(delta))

            return@OnGenericMotionListener true
        }

        false
    })
    

Java

    myView.setOnGenericMotionListener(new View.OnGenericMotionListener() {
        @Override
        public boolean onGenericMotion(View v, MotionEvent ev) {
            if (ev.getAction() == MotionEvent.ACTION_SCROLL && RotaryEncoder.isFromRotaryEncoder(ev)) {
                // Don't forget the negation here
                float delta = -RotaryEncoder.getRotaryAxisValue(ev) * RotaryEncoder.getScaledScrollFactor(
                getContext());

                // Swap these axes if you want to do horizontal scrolling instead
                v.scrollBy(0, Math.round(delta));

                return true;
            }

            return false;
        }
    });
    

エミュレータでロータリー入力ボタンをテストする

Android Emulator を使用すると、Wear デバイスでロータリー入力スクロールをシミュレートできます。そのためには、プロジェクトを実行するときにエミュレータで Wear アプリを起動するか、APK ファイルをエミュレータにドラッグしてインストールします。

エミュレータでロータリー入力をテストする手順は次のとおりです。

  1. SDK Manager の [SDK tools] タブで、Android Emulator 26.0.3 以降を入手します。
  2. API 25 を使用して AVD(Android Virtual Device)を作成します。

    Studio で、[Tools] > [Android] > [AVD Manager] を選択します。 API 25 を使用して新しい Wear デバイスを作成します。

  3. Android Studio からエミュレータを実行します。
  4. ロータリー入力スクロールを試してみます。

    オーバーフロー ボタン(エミュレータ ツールバーの下部にある 3 つの点)をクリックし、新しいウィンドウで [Rotary input] タブをクリックして、ロータリー入力インターフェースを開きます。

次の動画は、エミュレータでのロータリー入力を示しています。

フォーカスの動作に関するヒント

  • ビューに setFocusableInTouchMode(true) が含まれている場合はフォーカス可能です。これはデフォルトでは、スクロール可能なビュー(ScrollView など)と InputText にのみ当てはまります。
  • デフォルトでは、ビューをタップしても、ビューは(フォーカス可能でも)フォーカスされません。ビューをタップしたときにフォーカスされるようにするには、ビューでタップイベントをリッスンし、手動で View.requestFocus() を呼び出す必要があります。
  • Activity が作成されるとすぐに、ビュー階層内にある最初のフォーカス可能なビューが自動的にフォーカスされます。アクティビティにフォーカス可能なビューが複数ある場合、目的のビューがフォーカスされないことがあります。別のビューをフォーカスするには、<requestFocus /> タグを使用します(または、Activity.onResumeView.requestFocus を手動で呼び出します)。
  • アクティビティが作成された後にフォーカス可能なビューがアタッチまたは再表示された場合、現在フォーカスされているビューがなくても、それらのビューは自動的にはフォーカスされません。この場合、手動で View.requestFocus を呼び出す必要があります。
  • ロータリー入力イベントは、フォーカスされているビューにのみ送信されます。これらのイベントによってビュー階層が上に移動することはありません。フォーカスされているビューがない場合、または、フォーカスされているビューが View.onGenericMotionEvent から false を返した場合、(そのときに初めて)イベントが Activity.onGenericMotionEvent に送信されます。