Save 37% off PRO during our Black Friday Sale! »

意外と簡単?Navigation rail導入のお話

F46a37b9f855c245f72a07b04045216a?s=47 Tomoya Miwa
November 16, 2021

意外と簡単?Navigation rail導入のお話

F46a37b9f855c245f72a07b04045216a?s=128

Tomoya Miwa

November 16, 2021
Tweet

Transcript

  1. 意外と簡単?Navigation rail導入のお話 2021/11/16 Mobile勉強会 Wantedly × チームラボ tomoya0x00 1

  2. About me tomoya0x00 Twitter, GitHub Android U-NEXT Co., Ltd. 2

  3. 話す事と、話さない事 話す事 Bottom navigation導入済みアプリに、Navigation railを導入した話し ただし、実装しただけで未リリース 話さない事 Material Design 3

    Material Design 2前提の話しをします Jetpack Compose 従来のAndroid View上での話しをします 3
  4. 目次 Navigation Rail is 何? 具体的なBottom navigationとの使い分け条件 簡単に導入できる前提条件 実際の導入の流れ なぜ、選択済みアイテムが引き継がれているのか?

    U-NEXTアプリに追加で手を加えたところ まとめと感想 4
  5. Navigation Rail is 何? 5

  6. 6

  7. Usage The rail is a side navigation component that displays

    three to seven app destinations and, optionally, a Floating Action Button. Each destination is represented by an icon and a text label. The rail can function on its own at larger screen sizes, such as desktop and tablet. When users transition between screen sizes and devices, the rail can also complement other navigation components, such as bottom navigation. https://material.io/components/navigation-rail#usage 7
  8. When to use Navigation rails should be used for: Top-level

    destinations that need to be accessible anywhere in an app Three to seven main destinations in a product Tablet or desktop layouts Navigation rails shouldn’t be used for: Small screen sizes Single tasks, such as viewing a single email Secondary navigation destinations https://material.io/components/navigation-rail#usage 8
  9. 具体的なBottom navigationとの使い分け条件 9

  10. Create responsive navigation views https://developer.android.com/guide/topics/large-screens/navigation-for-responsive- uis#create_responsive_navigation_views 10

  11. Window size classes https://developer.android.com/guide/topics/large-screens/support-different-screen- sizes#window_size_classes 11

  12. 簡単に導入できる前提条件 12

  13. 簡単に導入できる前提条件 (1/2) Material Components for Android の BottomNavigationView を導入済み BottomNavigationViewを表示しているActivityでは、configuration

    changeを自前でハ ンドリング していない AndroidMafinext.xml で、該当Activityに android:configChanges という 記 載が無い 13
  14. 簡単に導入できる前提条件 (2/2) BottomNavigationView固有のメソッドを使っていない NavigationBarView で提供されているメソッドだけを使っているならOK NGなメソッド isItemHorizontalTranslationEnabled setItemHorizontalTranslationEnabled setOnNavigationItemReselectedListener 代わりに

    setOnItemReselectedListener を使う setOnNavigationItemSelectedListener 代わりに setOnItemSelectedListener を使う 14
  15. 実際の導入の流れ 15

  16. 実際の導入の流れ 1. 使用するMaterial Components for Androidのバージョンを1.4.0以上にする 2. 横幅600dp以上でレイアウトファイルを切り替えてNavigationRailViewを表示する 3. Activity側ではNavigationBarViewとしてキャストして使用する

    16
  17. 1. 使用するMaterial Components for Androidのバージョンを1.4.0以 上にする NavigationRailView は 1.4.0 から使用できるため

    app moduleのbuild.gradleなどを更新 implementation "com.google.android.material:material:1.4.0" 17
  18. 2. 横幅600dp以上でレイアウトファイルを切り替えて NavigationRailViewを表示する Create responsive navigation views を参考に、レイアウトファイルを分ける BottomNavigationViewを表示しているActivity(以降:MainActivity)のレイアウトフ ァイルを

    res/layout-w600dp/ にコピーして、 BottomNavigationView を NavigationRailView に書き換える app:layout_constraint* も表示位置に合わせて変更する 18
  19. コピー元:res/layout/main_activity.xml <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <com.google.android.material.bottomnavigation.BottomNavigationView android:id="@+id/nav_view" android:layout_width="0dp" android:layout_height="wrap_content" app:menu="@menu/main_nav_menu" app:layout_constraintBottom_toBottomOf="parent"

    app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" ... /> <!-- content view(s) --> </androidx.constraintlayout.widget.ConstraintLayout> 19
  20. コピー先:res/layout-w600dp/main_activity.xml <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <com.google.android.material.navigationrail.NavigationRailView android:id="@+id/nav_view" android:layout_width="wrap_content" android:layout_height="0dp" app:menu="@menu/main_nav_menu" app:layout_constraintBottom_toBottomOf="parent"

    app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" ... /> <!-- content view(s) --> </androidx.constraintlayout.widget.ConstraintLayout> 20
  21. レイアウトファイルの差分と補足 (1/2) com.google.android.material.bottomnavigation.BottomNavigationView -> com.google.android.material.navigationrail.NavigationRailView app:layout_constraintEnd_toEndOf="parent" -> app:layout_constraintTop_toTopOf="parent" android:layout_width と

    android:layout_height の値を入れ替え 記載を省略していますが、 content view(s) の app:layout_constraint* も変更 必要です 21
  22. レイアウトファイルの差分と補足 (2/2) android:id や app:menu はそのまま(同じ値を指定)にしておきます 自分は事前に共通っぽい(Bottom navigation固有では無い)名前にリネームしまし た android:id

    を同じにしておくと実装が楽ですが、後述の危険性もあるのでご留意 ください 22
  23. 3. Activity側ではNavigationBarViewとしてキャストして使用する before binding.navView.setOnItemSelectedListener { ... } after // binding

    上はView になってしまうので、キャストしている val navView = binding.navView as NavigationBarView navView.setOnItemSelectedListener { ... } 23
  24. これだけです 24

  25. ※ これらのスクショは開発中のもので、ロゴの追加やテキストスタイル調整をおこなっています 25

  26. ※ これらのスクショは開発中のもので、ロゴの追加やテキストスタイル調整をおこなっています 26

  27. 意外と簡単ですよね? 27

  28. ただ、疑問が一つ… 28

  29. なぜ、選択済みアイテムが引き継がれているのか? 29

  30. なぜ、選択済みアイテムが引き継がれているのか? なぜ、画面回転しても選択済みアイテムの状態が復元されているのか? BottomNavigationView と NavigationRailView は個別に onSaveInstanceState/onRestoreInstanceState を実装 していない 共通の親である

    NavigationBarView で状態の保存と復元をおこなっている NavigationBarView#onSaveInstanceState NavigationBarView#onRestoreInstanceState なので、レイアウトファイル上で同じView IDだと自動で保存と復元ができる ただし、将来的に個別に保存と復元処理が実装されると、壊れる危険性あり 30
  31. U-NEXTアプリに追加で手を加えたところ 31

  32. U-NEXTアプリに追加で手を加えたところ Windowの高さが低い場合、 Compact rail without text labels を参考に表示を微調整 ロゴ無し ラベル文字無し

    NavigationRailView の横幅を小さくして、各アイテムの高さを削減 コメント によると、 NavigationRailView の横幅 = 各アイテムの最小限の高さ val metrics = WindowMetricsCalculator.getOrCreate() .computeCurrentWindowMetrics(this) val heightDp = metrics.bounds.height() / resources.displayMetrics.density if (heightDp < 400) { navRail.removeHeaderView() navRail.labelVisibilityMode = NavigationRailView.LABEL_VISIBILITY_UNLABELED navRail.layoutParams.width = (56 * resources.displayMetrics.density).toInt() } 32
  33. ※ これらのスクショは開発中のもので、ロゴの追加やテキストスタイル調整をおこなっています 33

  34. ※ これらのスクショは開発中のもので、ロゴの追加やテキストスタイル調整をおこなっています 34

  35. まとめと感想 35

  36. まとめと感想 Bottom navigation導入済みであれば、Navigation railの導入は意外と簡単 View IDを共通にすると実装が楽だけど、今後壊れる可能性はあるので注意 個人的にスマホ横画面でのNavigation railは縦方向の表示領域が広がって嬉しい ただし、スマホ横画面でNavigation railに切り替わるアプリを見たことが無い

    例えば、 google/iosched では、 横幅720dp以上 で切り替えている ただ、時系列に 600dp以上で切り替えましょう が最新ガイドライン? 自分の場合、タブレットやスマホ横画面では両手で端末の両サイドを保持する ナビゲーションのUIが端末の横側に表示されるのは、操作しやすい気がする 36