Upgrade to Pro — share decks privately, control downloads, hide ads and more …

nacatl_slide_04_AAC_Navigation_Toolbar

nacatl
December 24, 2019
640

 nacatl_slide_04_AAC_Navigation_Toolbar

nacatl

December 24, 2019
Tweet

Transcript

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  7. Jetpack Navigation ライブラリ

    View full-size slide

  8. Jetpack Navigation ライブラリ

    View full-size slide

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

    View full-size slide

  10. Toolbar.setupWithNavController
    The Toolbar has a extension method.

    View full-size slide

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

    View full-size slide

  12. Toolbar.setupWithNavController
    NavGraphでラベル文字列を指定すると
    自動でToolbarに表示してくれる
    ~~
    android:label="@string/title_fragment_1">


    直書きもリソース指定も可能

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  16. Toolbar.setupWithNavController
    - デフォルトのAppBarConfigration

    View full-size slide

  17. Toolbar.setupWithNavController
    - デフォルトのAppBarConfigration

    View full-size slide

  18. 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

    View full-size slide

  19. 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()
    )

    View full-size slide

  20. 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  27. 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
    );
    }

    View full-size slide

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

    View full-size slide

  29. 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管理とか
    }

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  34. Toolbar in Fragment
    The Fragments have each Toolbar.

    View full-size slide

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

    View full-size slide

  36. まとめ
    Conclusion

    View full-size slide

  37. - 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)

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  40. 追加資料
    - バックスタックない時の根拠(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;
    }

    View full-size slide