アシアルブログ

アシアルの中の人が技術と想いのたけをつづるブログです

ジェスチャー ナビゲーションによる操作の干渉について

こんにちは、MonacaチームでMonacaの安定運用のために、いろんな検証をしている小田川です。

Android 10から、端末操作に ジェスチャー ナビゲーション が追加されています。

この ジェスチャー ナビゲーション は、これまでの画面下に表示されていた 戻る ボタンや ホーム ボタン、タスク表示 ボタン(3ボタン)をタップして画面の操作を行うのではなく、画面をスワイプすることで画面操作を行います。

ジェスチャー ナビゲーションでは、ホームに移動する場合は、画面下から上へスワイプします。 戻る操作は、左右の画面端から内側へスワイプします。

ジェスチャー ナビゲーションの操作に慣れていない時は、「3ボタン」の方が使いやすいように感じたのですが、慣れてしまうと「3ボタン」より楽に端末が操作できているように感じます。

ジェスチャー ナビゲーションとアプリの操作干渉

このジェスチャー ナビゲーションには、問題点もあります。

ジェスチャー ナビゲーションの 戻る 操作が、これまでの ドロワー を開くときのスワイプ操作に干渉し、ドロワーを引き出すつもりが、アプリが閉じてしまうというような動作になる場合があります。

このような干渉を回避するために ViewCompat.setSystemGestureExclusionRects() が用意されています。この ViewCompat.setSystemGestureExclusionRects() を利用することで、指定した範囲をジェスチャー ナビゲーションの適用範囲から除外することができます。

ドキュメント では、DrawerLayout および SeekBar コンポーネントは、setSystemGestureExclusionRects() の追加設定が不要になっているのですが、 androidx.drawerlayout:drawerlayout:1.1.0-alpha01 では、setSystemGestureExclusionRects() の処理が行われていますが、 androidx.drawerlayout:drawerlayout:1.1.0-alpha03 では、setSystemGestureExclusionRects() の処理から、画面の端から内側へスワイプした際にピーク動作が追加され、ドロワーが少し表示された後に引き出される というような動作に変更になっているようです。

実際にGmailアプリ操作してみると、画面端を少し長押しするようにすると、ドロワーが少し表示され、そのまま内側へスワイプすると、ドロワーが引き出されます。

画面端から素早く内側へスワイプした場合は、ジェスチャー ナビゲーションの操作と干渉してアプリが閉じてしまいました。

そのため、これまで通り画面端からスワイプしてドロワーを引出そうとすると、アプリが閉じてしまう場合があります。

setSystemGestureExclusionRects() を試してみる

setSystemGestureExclusionRects() を利用して、ジェスチャー ナビゲーションの適用範囲から除外することができるか試してみたいと思います。

この setSystemGestureExclusionRects() 除外できる範囲は、最大 200dp までとなっています。

今回は、Android Studio 3.5.2にある Navigation Drawer Activity テンプレートを使用します。テンプレートに設定されているライブラリーのバージョンが古い場合は、最新に更新します。

このテンプレートでは、MainActivityのonCreate()で、すでにDrawerLayoutを取得しているので、これを利用します。

f:id:keiji_asial:20191120164420g:plain

setSystemGestureExclusionRects()を設定しない場合は、ドロワーは引き出されず、ジェスチャー ナビゲーションの <> が表示されています。

下記のように、setSystemGestureExclusionRects()を設定してみます。下記の設定では、画面左下から上に 200dp の正方形の範囲を除外しています。

MainActivity.kt(抜粋)

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)

    drawerLayout.post {
        val exclusionRect = Rect()
        val exclusions = listOf(exclusionRect)
        
        val exclusionRectSize = 200.0f * this.resources.displayMetrics.density
        exclusionRect.set(drawerLayout.left, (drawerLayout.bottom - exclusionRectSize.toInt()), exclusionRectSize.toInt(), drawerLayout.bottom)
        ViewCompat.setSystemGestureExclusionRects(drawerLayout, exclusions)
    }
}

f:id:keiji_asial:20191120164510g:plain

上記の設定を行った場合、画面左下から上に 200dp の範囲で、画面左端からスワイプしてドロワーが引き出されました。

今回の検証で、ジェスチャー ナビゲーションとアプリの操作が干渉する場合は、setSystemGestureExclusionRects() で対応できることが分かりました。

Cordovaアプリでの対応

ネイティブアプリの場合は、setSystemGestureExclusionRects() で対応できましたが、Cordovaの場合は、Cordovaプラグインを使用して setSystemGestureExclusionRects() 対応する必要があります。

ドロワーが少し表示された後に引き出される という操作方法は、androidx.drawerlayout:drawerlayout:1.1.0-alpha03 の DrawerLayout が提供している機能になるため、Cordovaでアプリ開発を行う場合は、setSystemGestureExclusionRects() で対応する必要がありそうです。

setSystemGestureExclusionRects() は、AndroidXライブラリーで提供されています。Cordova 9.0では、標準ではAndroidXには対応していないため、

のような、AndroidXライブラリーに変換してくれるCordvaプラグインを利用する必要があります。

Cordovaプラグインを作成してみた

Cordovaでの setSystemGestureExclusionRects() の動作確認として、上の cordova-plugin-androidxcordova-plugin-androidx-adapter を利用して、setSystemGestureExclusionRects() を適用するCordpvaプラグインを作成してみました。

Cordovaアプリでは、idが android.R.id.content のFrameLayoutが使用されていたので、このレイアウトを使用して、画面左下から上に 200dp の正方形の範囲を除外しています。

このCordovaプラグインは、Javaで作成していますが、行っている処理内容は、上の MainActivity.kt と同じです。

Monacaで提供している Onsen UI V2 JS Splitter テンプレートを使用し、MonacaでAndroidデバッグビルドをして動作検証を行ってみましたが、正しく動作しているようです。

Android用のカスタムビルドデバッガーでも動作しました。

f:id:keiji_asial:20191120164531g:plain

対象のMonacaプロジェクトでは、config.xml の <widget> タグ直下に、下記の設定を行っています。

<preference name= "android-targetSdkVersion" value="29"/>

おわりに

GmailなどのGoogleアプリでは、ドロワーが少し表示された後に引き出される 形での操作になっているため、今後は、この操作方法が標準操作になりそうな感じです。

これまでの操作方法が変わるのは悩ましいところですが、今回の検証でジェスチャー ナビゲーションとアプリの操作が干渉した場合は、setSystemGestureExclusionRects() で対応できることが分かったので、他のアプリでの操作動向も注目しつつ、今後もジェスチャー ナビゲーションとアプリの操作干渉についてチェックしていきたいと思います。