🔲
Jetpack ComposeのHorizontalPagerにFragmentを埋め込み、各Fragmentに引数を渡す方法
概要
Jetpack ComposeにFragmentを埋め込む方法です。
埋め込むFragmentに引数を渡す必要があったのと、HorizontalPagerに複数のFragmentを埋め込みたいという事情がありました。
公式docがAndroidViewBinding
を勧めているので、最初このようにしました。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.compose.ui.platform.ComposeView
android:id="@+id/horizontal_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<androidx.fragment.app.FragmentContainerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container_view"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:name="com.vitantonio.nagauzzi.PageFragment" />
</androidx.constraintlayout.widget.ConstraintLayout>
HorizontalPager(count = argList.size) { page ->
AndroidViewBinding(RootFragmentBinding::inflate){
val fragment = fragmentContainerView.getFragment<PageFragment>()
fragment.arguments = argList[page]
}
}
しかし、クロージャー内が呼ばれる前にFragmentがinflate
されるのを避けられず、
java.lang.IllegalStateException: Fragment PageFragment{d4b9c8c} (00000000-0000-0000-0000-000000000000 id=0x00000000) has null arguments
となってしまいました。
色々調査して、AndroidViewBinding
では無理だと判断し、AndroidView
を使った方法で解決しました。
成功したコード
val fragments = argsList.map { args ->
PageFragment().apply {
arguments = args.bundle()
}
}
HorizontalPager(count = argsList.size) { page ->
AndroidView(factory = { context ->
val frameLayout = FrameLayout(context).apply {
id = R.id.container
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
}.also {
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(it.id, fragments[page])
transaction.commit()
}
frameLayout
}, update = {
// レイアウト後に外から何かを設定したい場合、fragments[page]を使う
})
}
補足
layoutParams
の設定は大事です。
今回HorizontalPager内のFragmentのViewが更にComposeを使っていて、その中のGlideが
compose java.lang.IllegalArgumentException: Failed requirement.
というエラーを出力し、原因がわからず悩んでいましたが、原因はlayoutParams
の設定忘れによる異常表示でした。
また、update
内でit.findFragment
でFragmentを取得しても良いかなと思ったんですが、
java.lang.IllegalStateException: View android.widget.FrameLayout{0000000 V.E...... ......I. 0,0-0,0 #00000000 app:id/container} does not have a Fragment set
と出力されてうまくいかず、時間オーバーで探究を避けて上記の方法に落ち着きました。
Discussion