Jetpack Compose中的碎片容器

18

我希望使用 Jetpack Compose 开发一个单 Activity 多 Fragment 的应用程序。对于 recyclerView,我们有 Vertical 和 HorizontalScroller。但是,对于 fragments 我该使用什么呢。


fun loadFragment(fragment: Fragment) {
            val transaction:FragmentTransaction = supportFragmentManager.beginTransaction()
            transaction.replace(R.id.f_container, fragment)
            transaction.addToBackStack(null)
            transaction.commit()
        }
在这种情况下,我没有R.id.f_container,因为我只使用Compose创建UI。
<FrameLayout
    android:id="@+id/f_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"`enter code here`
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    app:layout_constraintEnd_toEndOf="parent"
    tools:layout_editor_absoluteY="-56dp">
</FrameLayout>

2
片段需要一个ViewGroup容器。这一点不太可能改变。因此,如果您想继续使用片段,您将需要在适当的位置放置一个ViewGroup。目前,由于Compose/view互操作性仍然是“正在进行中”的状态,这可能意味着您的片段需要进入传统布局。 - CommonsWare
@Thaw De Zin 如果你已经找到了问题的解决方案,请让我知道。 - divine
这可能会解决你的问题:https://medium.com/mobile-app-development-publication/load-fragments-in-jetpack-compose-beyond-what-google-taught-356a7981268d?sk=43b363c34040c646454d1629ef5f504b - Elye
使用 AndroidViewBinding 加载一个 navhost fragment(可能带有 nav graph),然后通过 Navigation 组件,您基本上也可以在此场景中导航到呈现 Compose 的片段。https://developer.android.com/jetpack/compose/migrate/interoperability-apis/views-in-compose#androidview_with_view_binding - Kevin Constantine
3个回答

10
您可以创建自己的@Composable FragmentContainer函数。
@Composable
fun FragmentContainer(
    modifier: Modifier = Modifier,
    fragmentManager: FragmentManager,
    commit: FragmentTransaction.(containerId: Int) -> Unit
) {
    val containerId by rememberSaveable { mutableStateOf(View.generateViewId()) }
    var initialized by rememberSaveable { mutableStateOf(false) }
    AndroidView(
        modifier = modifier,
        factory = { context ->
            FragmentContainerView(context)
                .apply { id = containerId }
        },
        update = { view ->
            if (!initialized) {
                fragmentManager.commit { commit(view.id) }
                initialized = true
            } else {
                fragmentManager.onContainerAvailable(view)
            }
        }
    )
}

/** Access to package-private method in FragmentManager through reflection */
private fun FragmentManager.onContainerAvailable(view: FragmentContainerView) {
    val method = FragmentManager::class.java.getDeclaredMethod(
        "onContainerAvailable",
        FragmentContainerView::class.java
    )
    method.isAccessible = true
    method.invoke(this, view)
}

然后在活动中使用它

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
        FragmentContainer(
            modifier = Modifier.fillMaxSize(),
            fragmentManager = supportFragmentManager,
            commit = { add(it, YourFragment()) }
        )
    }
}

或者是片段

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View = ComposeView(requireContext()).apply {
    setContent {
        FragmentContainer(
            modifier = Modifier.fillMaxSize(),
            fragmentManager = parentFragmentManager,
            commit = { add(it, YourNestedFragment()) }
        )
    }
}

1
这需要使用Fragment KTX库,例如 implementation "androidx.fragment:fragment-ktx:1.4.1" - Elye
1
虽然上述方法可行,但是如 https://medium.com/mobile-app-development-publication/load-fragments-in-jetpack-compose-beyond-what-google-taught-356a7981268d?sk=43b363c34040c646454d1629ef5f504b 所述,仍存在一些限制。 - Elye

3
我建议您不要重复使用现有的片段,而是尝试回收其内部视图以创建新的可组合项。
无论如何,如果您想玩一下,这里有一个可能的解决方案:
AndroidView(
modifier = Modifier
    .fillMaxHeight()
    .fillMaxWidth(),
factory = { context ->
    FrameLayout(context).apply {
        FragmentBlankBinding.inflate(LayoutInflater.from(context), this, true).root
    }
})

祝您愉快!


-4

如果您正在创建一个新的应用程序,您可以完全跳过使用Fragments,而只是使用可组合函数来表示您的屏幕。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接