Slide 1

Slide 1 text

Copyright 2018 Studyplus, Inc. All Rights Reserved. Jetpack Navigation Toolbarのいろいろ Yuzuru Nakashima / Studyplus Inc. 2019.12.24 @ あるあるLT Vol.09

Slide 2

Slide 2 text

自己紹介 ✎ なかてぃる affinity_robots nacatl ✎ スタディプラスのAndroidエンジニア ✎ 趣味: Magic the Gathering ✎ DroidKaigi2020登壇します!

Slide 3

Slide 3 text

MISSION 「学ぶ喜びをすべての人へ」 多くの人がStudyplusを通じて学習のきっかけを見つけ、 学習を楽しく継続できることを実現する。 会社紹介

Slide 4

Slide 4 text

アジェンダ ✎ Jetpack Navigation ライブラリ ✎ Toolbar.setupWithNavController ✎ onDestinationChangedListener ✎ ViewModel経由 ✎ Toolbar in Fragment ✎ まとめ

Slide 5

Slide 5 text

Jetpack Navigation ライブラリ Fragment画面遷移の改革

Slide 6

Slide 6 text

Jetpack Navigation ライブラリ - Fragmentによる画面遷移を視覚的に デザインできるライブラリ - Fragment遷移のバックスタックとかも 管理してくれる - NavGraphというxmlで遷移を管理

Slide 7

Slide 7 text

Jetpack Navigation ライブラリ

Slide 8

Slide 8 text

Jetpack Navigation ライブラリ

Slide 9

Slide 9 text

Jetpack Navigation ライブラリ Navigationでリファクタリングする場合、 今までActivityで管理してたツールバーとか どうするの?

Slide 10

Slide 10 text

Toolbar.setupWithNavController The Toolbar has a extension method.

Slide 11

Slide 11 text

Toolbar.setupWithNavController - ToolbarをNavigationで管理する拡張関数 - ラベル文字列をNavGraphで指定できる - 「←」ボタン表示有無 - バックスタックない時の「←」挙動の管理 - AppCompatActivity.setupWithActionBar WithNavControllerもあるけどまた今度 (DrawerNavigationと連携とかできる)

Slide 12

Slide 12 text

Toolbar.setupWithNavController NavGraphでラベル文字列を指定すると 自動でToolbarに表示してくれる 直書きもリソース指定も可能

Slide 13

Slide 13 text

Toolbar.setupWithNavController fun Toolbar.setupWithNavController( navController: NavController, configuration: AppBarConfiguration = AppBarConfiguration(navController.graph) ) { NavigationUI.setupWithNavController( this, navController, configuration ) }

Slide 14

Slide 14 text

Toolbar.setupWithNavController fun Toolbar.setupWithNavController( navController: NavController, configuration: AppBarConfiguration = AppBarConfiguration(navController.graph) ) { NavigationUI.setupWithNavController( this, navController, configuration ) } このコンフィグで色々設定する

Slide 15

Slide 15 text

Toolbar.setupWithNavController val navController = findNavController(R.id.nav_host_fragment) // default findViewById(R.id.toolbar) .setupWithNavController(navController)

Slide 16

Slide 16 text

Toolbar.setupWithNavController - デフォルトのAppBarConfigration

Slide 17

Slide 17 text

Toolbar.setupWithNavController - デフォルトのAppBarConfigration

Slide 18

Slide 18 text

1 Activity Multi Fragmentの風を感じる ※ この辺りに載ってる思想をデフォルトにして設計されていると思って良さそう https://developer.android.com/guide/navigation/navigation-principles?hl=ja#u p_and_back_are_identical_within_your_apps_task Toolbar.setupWithNavController

Slide 19

Slide 19 text

Toolbar.setupWithNavController val navController = findNavController(R.id.nav_host_fragment) // TopLevelDestinationのSetを指定 val idSet = mutableSetOf() navController.graph.iterator() .forEach { idSet.add(it.id) } findViewById(R.id.toolbar) .setupWithNavController( navController, AppBarConfiguration.Builder(idSet).build() )

Slide 20

Slide 20 text

Toolbar.setupWithNavController val navController = findNavController(R.id.nav_host_fragment) // TopLevelDestinationのSetを指定(全部) val idSet = mutableSetOf() navController.graph.iterator() .forEach { idSet.add(it.id) } findViewById(R.id.toolbar) .setupWithNavController( navController, AppBarConfiguration.Builder(idSet).build() ) graphにあるも の全部 add

Slide 21

Slide 21 text

- 全部TopLevelDestinationに指定した場合 Toolbar.setupWithNavController

Slide 22

Slide 22 text

- 全部TopLevelDestinationに指定した場合 Toolbar.setupWithNavController

Slide 23

Slide 23 text

Toolbar.setupWithNavController - TopLevelDestinationを空で指定した場合 // TopLevelDestinationのSetを指定 (空)toolbar.setupWithNavController( navController, AppBarConfiguration.Builder(setOf()) .build() )

Slide 24

Slide 24 text

- TopLevelDestinationを空で指定した場合 Toolbar.setupWithNavController

Slide 25

Slide 25 text

- TopLevelDestinationを空で指定した場合 Toolbar.setupWithNavController ここの挙動は指定が必要

Slide 26

Slide 26 text

Toolbar.setupWithNavController - バックスタックがない時の「←」キー制御 // TopLevelDestinationのSetを指定 (空)toolbar.setupWithNavController( navController, AppBarConfiguration.Builder(setOf()) .setFallbackOnNavigateUpListener { onBackPressed() true }.build() )

Slide 27

Slide 27 text

Toolbar.setupWithNavController - Tips. ドロワーの場合ハンバーガー出るらしい // androidx.navigation.ui.AbstractAppBarOnDestinationChangedListener boolean isTopLevelDestination = NavigationUI .matchDestinations( destination, mTopLevelDestinations ); if (drawerLayout == null && isTopLevelDestination) { setNavigationIcon(null, 0); } else { setActionBarUpIndicator( drawerLayout != null && isTopLevelDestination ); }

Slide 28

Slide 28 text

NavController.addOnDestinationChangedListener The listener that is called when a current destination is changed.

Slide 29

Slide 29 text

onDestinationChangedListener // toolbar設定 setSupportActionBar(toolbar) supportActionBar?.let { it.setDisplayHomeAsUpEnabled(true) it.setHomeButtonEnabled(true) } // addOnDestinationChangedListener navController.addOnDestinationChangedListener { controller, destination, arguments -> supportActionBar?.title = destination.label // when(destination.id)でOptionMenu管理とか }

Slide 30

Slide 30 text

- 慣れてる感じで書ける - NavGraph.xmlに書いたラベルも渡せる - invalidateOptionsMenu()などはここが楽そう - 画面遷移時に何かしたいときもこれ追加で onDestinationChangedListener

Slide 31

Slide 31 text

ViewModel経由でLiveData Observe a liveData that is set value when a Fragment is created.

Slide 32

Slide 32 text

ViewModel経由でLiveData // 従来の設定 setSupportActionBar(toolbar) supportActionBar?.let { it.setDisplayHomeAsUpEnabled(true) it.setHomeButtonEnabled(true) } // LiveDataのObserverで変更 viewModel.titleText.observe(this) { title -> supportActionBar?.title = title }

Slide 33

Slide 33 text

- 慣れてる感じで書ける - ランタイムでタイトルが変わるとかだと有用 - invalidateOptionsMenu()なども 別口でLiveData用意するとかで ViewModel経由でLiveData

Slide 34

Slide 34 text

Toolbar in Fragment The Fragments have each Toolbar.

Slide 35

Slide 35 text

Toolbar in Fragment - Toolbarを各Fragmentのレイアウトで持つ - 個別に細かいカスタマイズがあるなら - OptionMenuの中身が細かく切り替わる - 「←」じゃなく「×」ボタン付けたい - デザイン的カスタマイズ

Slide 36

Slide 36 text

まとめ Conclusion

Slide 37

Slide 37 text

- NavigationライブラリはGoogleの ドクトリンに沿って開発されている https://developer.android.com/guide/navigation/navigation-principles?hl=ja#u p_and_back_are_identical_within_your_apps_task(再喝) - 私見: できる限りNavigationに乗っかりたい (Toolbar.setupWithNavController) (OnDestinationChangedListener) (AppCompatActivity .setupActionBarWithNavController)

Slide 38

Slide 38 text

- でもやっぱり案件ごとに色々あるよね… ケースバイケースで選びましょう - setupWith〜使いつつ一箇所だけLiveDataや ChangedListener内で上書きなど、 併用も考慮

Slide 39

Slide 39 text

ご静聴ありがとうございました

Slide 40

Slide 40 text

追加資料 - バックスタックない時の根拠(2.2.0-rc04の内部コード ) // androidx.navigation.ui.AppBarConfiguration /** * The {@link OnNavigateUpListener} that should be invoked if * {@link androidx.navigation.NavController#navigateUp} returns false. * @return a {@link OnNavigateUpListener} for providing custom up navigation logic, * if one was set. */ @Nullable public OnNavigateUpListener getFallbackOnNavigateUpListener() { return mFallbackOnNavigateUpListener; }