ロータリー入力

一部の Wear OS デバイスには、物理的な回転サイドボタンが配置されています。ユーザーがボタンを回すと、アプリの現在のビューが上または下にスクロールします。このタイプの入力はロータリー入力と呼ばれます。

注: このガイドでは、主にビューベースの UI を使用してロータリー入力を処理する方法について説明します。Wear OS 向け Compose を使用したロータリー入力の処理について詳しくは、Compose のロータリー入力をご覧ください。

ScrollViewListViewHorizontalScrollViewWearableRecyclerView など、スクロール可能なコンテナの多くは、フォーカスされている場合に Wear OS 固有のコードを必要とすることなくロータリー入力をサポートします。Android 9(API レベル 28)以降では、ビューが暗黙的にフォーカスを受け取ることはないため、フォーカスされていることは重要な前提条件です。

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

ロータリー入力イベントに応答するには、スクロール可能なコンテナがフォーカスされている必要があります。 ロータリー入力イベントによってビュー階層が上に移動することはありません。フォーカスされているビューがない場合、またはフォーカスされているビューが View.onGenericMotionEvent() から false を返す場合、イベントは Activity.onGenericMotionEvent() に送信されます。

ロータリー入力イベントへの応答に関するおすすめの方法は次のとおりです。

  • デフォルトでは、アクティビティを起動しても、またはビューをタップしても、ビューは(フォーカス可能であっても)フォーカスされないことに注意してください。ビューがフォーカスされるようにするには、ビューで <requestFocus /> タグを使用するか、手動で View.requestFocus() を呼び出す必要があります。
  • android:focusable="true"android:focusableInTouchMode="true" の両方を使用して、スクロール可能なカスタムビューをフォーカス可能としてマークします。
  • スクロール可能なビューが Activity.onCreate() の後にアタッチされる場合(たとえば、UI を構築する前にネットワーク リクエストが終了するのを待機する場合)は、ビューがアタッチされた後に requestFocus() を呼び出します。
  • スクロール可能なビューが初期段階で INVISIBLE または GONE であった場合は、VISIBLE に設定する際に requestFocus() を呼び出します。
  • アクティビティにスクロール可能なビューが複数含まれている場合は、<requestFocus /> タグでフォーカスするビューを 1 つ選択します。回転するサイドボタンでは、ネストされたスクロールはサポートされていません。
  • ユーザーが操作したときにフォーカスを受け取る他のビュー(InputText など)が UI に含まれている場合は、フォーカスを失ったときにスクロール可能なビューにフォーカスを復元する方法をユーザーに示します。これを行うには、スクロール可能なビューのタップをリッスンし、タップされたときに requestFocus() を呼び出します。

カスタムのローテーション動作

スクロール可能なビューがロータリー入力スクロールをネイティブにサポートしていない場合や、スクロール以外の目的でロータリー入力を使用する場合(ズームイン / ズームアウト、ダイヤルの回転など)は、スクロール イベントをご自分で処理できます。必ずビューがフォーカスされるように設定してください。そのように設定しないと、イベントは発生しません。

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

Kotlin

myView.setOnGenericMotionListener { v, ev ->
  if (ev.action == MotionEvent.ACTION_SCROLL &&
      ev.isFromSource(InputDeviceCompat.SOURCE_ROTARY_ENCODER)
  ) {
    // Don't forget the negation here
    val delta = -ev.getAxisValue(MotionEventCompat.AXIS_SCROLL) *
        ViewConfigurationCompat.getScaledVerticalScrollFactor(
             ViewConfiguration.get(context), context
        )
    // Swap these axes to scroll horizontally instead
    v.scrollBy(0, delta.roundToInt())
    true
  } else {
    false
  }
}

Java

myView.setOnGenericMotionListener(new View.OnGenericMotionListener() {
  @Override
  public boolean onGenericMotion(View v, MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_SCROLL &&
        ev.isFromSource(InputDeviceCompat.SOURCE_ROTARY_ENCODER)
    ) {
      // Don't forget the negation here
      float delta = -ev.getAxisValue(MotionEventCompat.AXIS_SCROLL) *
          ViewConfigurationCompat.getScaledVerticalScrollFactor(
               ViewConfiguration.get(context), context
          );

      // Swap these axes to scroll horizontally instead
      v.scrollBy(0, Math.round(delta));

      return true;
    }
    return false;
  }
});

エミュレータを使用してテストする

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

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

  1. SDK Manager の [SDK Tools] タブで、Android Emulator 26.0.3 以降を入手します。
  2. Android Studio で、[Tools] > [Android] > [AVD Manager] を選択します。 API 25 以降を使用して新しい Wear デバイスを作成します。
  3. Android Studio からエミュレータを実行します。
  4. エミュレータ ツールバーの下部にあるオーバーフロー メニュー(3 つの点)をクリックします。新しいウィンドウで [Rotary input] タブをクリックしてロータリー入力インターフェースを開き、ロータリー入力のスクロールを試みます。

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