ユニファ開発者ブログ

ユニファ株式会社プロダクトデベロップメント本部メンバーによるブログです。

ViewPager2 とAndroid Jetpack Navigationを使ってみる

この記事は、ユニファ Advent Calendar 2021の11日目の記事です。

adventar.org

こんにちはプロダクトエンジニアリング部のあいばです。

今回はユニファが今年9月にリリースしたAndroid アプリの実装の一部を紹介したいと思います。 lookmee.jp

ルクミー for FAMILY には、園・施設と保護者のやりとりをスムーズにするための様々な機能がありますが、その中でも画面が少し複雑な連絡帳の機能をとりあげます。

画面構成

連絡帳画面の機能は大きく2つのタブに分かれていて、家庭から送信する連絡帳と園から送信された連絡帳をスワイプで切り替えることができます。 さらに家庭からの連絡帳には4つの状態があり、①登園、②欠席、③登園送信済み、④欠席送信済み、と切り替わります。

f:id:unifa_tech:20211208161023j:plain:w300
連絡帳を作成する画面

レイアウト構成はこのようにしました。 Fragmentがネストしていてなかなか複雑な構造ですね!

f:id:unifa_tech:20211208174126p:plain
連絡帳画面の構成

ともかく、デザインを実現することはできました。 が、まだNavigation に課題があります。

DialogFragmentの入力結果を受け渡したい

①登園用画面(以降、PresenceCombookFragment)では入力フォームがたくさんあり、DialogFragmentを利用して値を入力します。
DialogFragmentを表示するだけなら、ルートにあるNavHostFragmentの nav graphを利用すれば可能ですが、DialogFragmentからPresenceCombookFragmentに入力結果を渡すために少し手間が必要でした。
DialogFragment と Fragment 間でデータを共有する方法は以下の2つがあるかと思います。

  1. ViewModel を使用してデータを共有する
  2. Fragment Result API を使用して結果を取得する

フラグメント間でデータを渡す  |  Android デベロッパー  |  Android Developers

今回はDialogFragmentでの入力結果について1回限りの受け渡しを行うのでFragment Result API を使用することにしました。しかし、Fragment Result APIを使用するにはFragment間に親子関係が必要です。PresenceCombookFragmentはViewPager2でインスタンス化されているので nav graph の管理外です。

ViewPager2にNavHostFragmentを入れてみる

PresenceCombookFragmentが含まれる nav graph が必要なため、PresenceCombookFragmentがあった場所にNavHostFragmentを入れます。

f:id:unifa_tech:20211209085432p:plain
最終的な画面構成

class PresenceCombookNavHostFragment : BaseFragment() {

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?,
    ): View {
        return FragmentNavHostPresenceBinding.inflate(inflater, container, false).root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val nestedNavHostFragment =
            childFragmentManager.findFragmentById(R.id.presenceNavHost) as? NavHostFragment
    }
}

ViewPager2のAdapterで生成してます。

    override fun createFragment(position: Int): Fragment {
        return when (HomeCombookPage.values()[position]) {
            0 -> PresenceCombookNavHostFragment()
            1 -> AbsenceCombookFragment()
            2 -> SubmittedPresenceCombookFragment()
            3 -> SubmittedAbsenceCombookFragment()
        }
    }

startDestination にPresenceCombookFragment を指定します。

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/presence_combook_navigation"
    app:startDestination="@id/presenceCombookFragment">

    <fragment
        android:id="@+id/presenceCombookFragment"
        android:name="com.unifa_e.sample.PresenceCombookFragment"
        android:label="PresenceCombookFragment">
        <action />
    </fragment>

できました!

f:id:unifa_tech:20211209085614g:plain
体温を入力してみよう

おわりに

なんとか実装できました!まだまだ改善の余地がありますが、ルクミー for FAMILY が保育施設の方々、保護者の方々のお役に立てると嬉しいです。
今後もサービスの改善に努めます!

XMLがまだまだ主力ですが、ユニファではJetpack compose 導入してこうぜと燃えるAndroidエンジニアも募集中です!

unifa-e.com