$30 off During Our Annual Pro Sale. View Details »

Jetpack Composeでの画面遷移

Jetpack Composeでの画面遷移

iwata naoki

June 30, 2022
Tweet

Other Decks in Programming

Transcript

  1. Jetpack Composeでの画面遷移

    2022/06/30
    Jetpack Compose 導入事例【おいしい健康|Retty|ZOZO|アンドパッド】

    株式会社ZOZO

    ZOZOTOWNアプリ部 Android1ブロック

    Androidテックリード

    岩田直樹(いわたん)

    Copyright © ZOZO, Inc.
    1

    View Slide

  2. © ZOZO, Inc.
    株式会社ZOZO

    ZOZOTOWNアプリ部 Android1ブロック

    Androidテックリード

    岩田直樹(いわたん)

    @iwata_n

    普段は二児の父親をやってます。

    Androidアプリのコードを仕事で書いてます。

    2

    View Slide

  3. © ZOZO, Inc.
    https://zozo.jp/

    3
    ● ファッションEC

    ● 1,500以上のショップ、8,400以上のブランドの取り扱い

    ● 常時90万点以上の商品アイテム数と毎日平均2,600点以上の新着 商
    品を掲載(2022年3月末時点)

    ● ブランド古着のファッションゾーン「ZOZOUSED」や

    コスメ専門モール「ZOZOCOSME」、靴の専門モール

    「ZOZOSHOES」、ラグジュアリー&デザイナーズゾーン

    「ZOZOVILLA」を展開

    ● 即日配送サービス

    ● ギフトラッピングサービス

    ● ツケ払い など


    View Slide

  4. © ZOZO, Inc.
    コンテンツ

    1. 概要と結論

    2. 検討内容

    3. 移行を見据えた実装方法

    4

    View Slide

  5. © ZOZO, Inc.
    コンテンツ

    1. 概要と結論

    2. 検討内容

    3. 移行を見据えた実装方法

    5

    View Slide

  6. © ZOZO, Inc.
    概要

    Jetpack Composeを使用した画面遷移に関して、公式ドキュメントには以下の記述があります。

    そこで今回は、なぜ公式ドキュメントではFragmentの使用をオススメしているのか、

    公式ドキュメントとは逆にComposeからFragmentを利用する形で検証します。

    また、公式ドキュメントに従ってFragmentをComposableのラッパーとした場合、

    どのようにComposeを実装していき移行するかを画面遷移の観点でまとめます。


    『ハイブリッド アプリの場合は、フラグメント ベースの Navigation コンポーネントを使用するとともに、ビューベースの画面、
    Compose の画面、およびビューと Compose の両方を使用する画面を保持するフラグメントを使用することをおすすめします。ま
    ず、アプリの各画面フラグメントをコンポーザブルのラッパーにします。次に、それらの画面すべてを一緒に Navigation Compose に
    関連付けて、すべてのフラグメントを削除します。』
    Android Developers Compose を使用したナビゲーションより引用
    https://developer.android.com/jetpack/compose/navigation?hl=ja#interoperability



    6

    View Slide

  7. © ZOZO, Inc.
    結論

    7
    ● Jetpack Composeでの画面遷移は公式ドキュメントの記載通りにFragmentでComposeをラップする実装で行うと問
    題点が少なく実装が可能です

    ● 既存実装が残る限りJetpack ComposeのNavigationは使うのが難しい

    ○ Jetpack Composeと既存実装が併存する間、新規画面は移行を考えた実装が必要です


    View Slide

  8. © ZOZO, Inc.
    コンテンツ

    1. 概要と結論

    2. 検討内容

    3. 移行を見据えた実装方法

    8

    View Slide

  9. © ZOZO, Inc.
    検討内容

    以下の画面遷移の方法について検討しました


    1. Compose→Fragmentとなる遷移

    2. Compose→Fragment→Fragmentとなる遷移

    3. Compose→Fragment→Composeとなる遷移

    9

    View Slide

  10. © ZOZO, Inc.
    Compose→Fragmentとなる遷移

    Navigation Componentを使っている場合は公式ドキュメントの通りで良い。

    FragmentManagerを使っている場合も、同様に公式ドキュメント相当の実装で実現可能です。

    https://developer.android.com/jetpack/compose/navigation?hl=ja#navigate-from-Compose

    10
    公式サイトの例はComposable側にXMLで定義したIDが入っているので移行時に少し改修が必要になる。

    Compose移行時に改修を不要にするためにコールバックに渡す引数は遷移先ではなく、遷移時に必要なパラメータ
    をわたすようにする。

    Compose Fragment
    Compose Fragment
    FragmentManagerでの遷移もこの
    コールバック内で出来る
    Compose内でXMLへ依
    存がある

    View Slide

  11. © ZOZO, Inc.
    Compose→Fragment→Fragmentとなる遷移

    11
    ● ComposeのAndroidViewにFragmentContainerViewを指定してNavHostFragmentを表示する

    ○ NavHostFragmentを使わず、既存実装のFragmentを表示するとfindNavController()を実行時に、
    NavHostFragmentが見つからずクラッシュする


    NavHostFragmentを用意してAndroidViewで表示す
    ることでfindNavController()が動くようにする

    View Slide

  12. © ZOZO, Inc.
    Compose
    (NavGraph)
    Compose→Fragment→Fragmentとなる遷移

    NavHostFragmentを使用した場合、一見画面遷移できているように見えるが、

    Compose側が戻るボタンの処理をフックしてしまいFragmentB→Aの戻る操作が正しく行えない。


    ①Compose→②FragmentA→③FragmentB→戻るボタンとした際に

    期待値は②のFragmentAが表示されることだが、実際には①Composeまで戻ってしまう。

    12
    Compose
    (AndroidView)
    親Fragment(NavHostFragment)
    ②Fragment A
    findNavController()
    ③Fragment B
    ①Compose
    Composeの遷移
    Navigation Componentの遷移
    戻る処理
    こちらが戻る処理を
    フックしてしまう

    View Slide

  13. © ZOZO, Inc.
    Compose→Fragment→Composeとなる遷移

    FragmentからJetpack Composeへ遷移する際にFragment側に改修が必要になる。

    例えばリストがFragment、詳細がComposeで実装されていた場合などで、

    リストから詳細へ遷移する際にクリックイベントをJetpack Comoseへ引き回してくる必要がある。

    → Fragment Result APIで取れるが、既存実装を改修するのであればCompose化を考えたほうが良さそう。


    13
    Compose
    (NavGraph)
    Compose
    (AndroidView)
    Fragment
    (リスト画面)
    Compose
    (詳細画面)
    選択結果
    Fragmentでの選択結果をFragment
    Result APIでComposeに渡す

    View Slide

  14. © ZOZO, Inc.
    検討結果

    ● Composeで既存実装をラップする実装をするには、既存実装側に手を入れる必要があったり、戻る操作を正しく実現
    するのに難がある

    ○ 公式ドキュメントではFragmentでComposableをラップするのをオススメしていたと思われる

    ○ 大半の画面をComposeで実装しても、移行するのが辛い既存実装があると完全にComposeのNavigationに移行は
    できない

    ● 併用が必要になるのが間違いないので新規実装時にComposeへ移行することを見据えた実装が必要になる


    14

    View Slide

  15. © ZOZO, Inc.
    コンテンツ

    1. 概要と結論

    2. 検討内容

    3. 移行を見据えた実装方法

    15

    View Slide

  16. © ZOZO, Inc.
    移行を見据えて既存実装とJetpack Composeを併用する

    新しい画面の実装手順

    1. Jetpack ComposeでステートレスなComposableをScreenとして実装する

    2. ViewModelを実装する

    3. Screenと、ステートや遷移イベントと紐付けを行うRouteを実装する

    4. Jetpack Compose内での遷移定義するNavigationを実装する

    5. RouteにThemeとNavigationを紐付けるFragmentを実装する

    6. 既存の画面遷移方法で新規Fragmentへ遷移する



    16
    既存NavHostFragment
    既存Fragment
    (手を加えない)
    新規Fragment
    ComposeView
    (NavHost)
    Compose
    Screen A
    Compose
    Screen B
    新規Fragment
    Composeの遷移
    Navigation Componentの遷移
    戻る処理

    View Slide

  17. © ZOZO, Inc.
    Jetpack ComposeでステートレスなScreenを実装する

    ● Screenは引数でステートを受け取り、イベントをコールバック
    で返す

    ● ScreenではViewModelを引数に取らない

    ○ Previewをしやすくする

    ○ 不要な再Composeを減らす


    17
    既存NavHostFragment
    既存
    Fragment
    新規Fragment
    ComposeView
    (NavHost)
    Compose
    Screen A
    Compose
    Screen B
    新規
    Fragment
    Tips

    ● Screenの単位でTopBarを定義した方がタイトルやメニューを各Screenから
    TopBarを管理する画面へ状態を伝える必要がなくなるので楽になる


    View Slide

  18. © ZOZO, Inc.
    ViewModelを実装する

    ● 画面の状態を管理するUiStateをStateFlowで提供する

    ● 副作用を流すためのEffectをSharedFlowで提供する



    18

    View Slide

  19. © ZOZO, Inc.
    Routeの実装

    ● Screenとステートや遷移イベントと紐付けを行うRouteを実装


    19
    既存NavHostFragment
    既存
    Fragment
    新規Fragment
    ComposeView
    (NavHost)
    Compose
    Screen A
    Compose
    Screen B
    新規
    Fragment
    Navigation ComponentではViewModelで遷移時のパラメータ (id)
    を受け取れなかったので Routeで指定できるようにする
    ここでScreenにUIの状態を渡す

    View Slide

  20. © ZOZO, Inc.
    NavigationGraphの定義

    ● NavGraphBuilderの拡張関数で画面遷移の定義を行う

    ● routeで{}を使うことで画面遷移時に渡すパラメータを設定できるが、FragmentでstartDestinationに遷移してきた際
    に値が取れなかったので、拡張関数のグラフで値を受け取る対策をした実装で定義する

    20
    理想形
    対策した実装
    既存NavHostFragment
    既存
    Fragment
    新規Fragment
    ComposeView
    (NavHost)
    Compose
    Screen A
    Compose
    Screen B
    新規
    Fragment

    View Slide

  21. © ZOZO, Inc.
    Fragmentの実装

    ● FragmentのonCreateViewでNavHostを定義したComposeViewを返す

    ● Composeに完全移行した際には不要になる

    ○ Fragmentでテーマを設定することでComposeに移行時に大本でComposableのテーマを設定するだけで全体に
    反映できるようになる

    21
    既存NavHostFragment
    既存
    Fragment
    新規Fragment
    ComposeView
    (NavHost)
    Compose
    Screen A
    Compose
    Screen B
    新規
    Fragment

    View Slide

  22. © ZOZO, Inc.
    完全にComposeに移行する

    移行手順

    1. 各フローごとにNavGraphBuilderの拡張関数でグラフを定義する

    2. アプリ全体の遷移を管理するNavHostで各フローを定義する

    3. 一番大本のComposableでテーマを設定する

    4. Fragmentを削除し、Navigation Componentを外す

    22

    View Slide

  23. © ZOZO, Inc.
    まとめ

    ● Jetpack Composeでの画面遷移は公式ドキュメントの記載通りにFragmentでComposeをラップする実装で行うと問
    題点が少なく実装が可能です

    ● 既存実装が残る限りJetpack ComposeのNavigationは使うのが難しい

    ○ Jetpack Composeと既存実装が併存する間、新規画面は移行を考えた実装が必要です


    23

    View Slide

  24. View Slide

  25. © ZOZO, Inc.
    Appendix

    25

    View Slide

  26. © ZOZO, Inc.
    Navigationの定義方法

    1. 機能やフローなど意味のある単位ごとにNavGraphBuilderの拡張関数を定義する

    2. NavGraphBuilderの拡張関数を使ってアプリ全体の画面遷移をまとめる

    26
    個別の機能やフローごとに拡張関数を定義 AppNavHostで全体をまとめる

    View Slide

  27. © ZOZO, Inc.
    BottomNavigation

    ScaffoldのbottomBarにBottomNavigationを指定するだけで作れるので便利。

    27
    enumで定義した設定値を forEachす
    るだけで要素が作れて便利
    click時にnavControllerで遷移させる
    enumに遷移先、テキスト、アイコンを
    定義する

    View Slide