我正在尝试将
TabRow
与 FragmentContainerView
中显示的现有片段结合起来实现。当子片段添加到活动/主机片段时,它们可以正常工作。但是在活动重新启动时,片段似乎不可见,但存在于片段管理器中,但由于某种原因没有显示。由于我们现有的实现/架构,我们只能添加片段而不能替换它们。下面是它的示例代码。 Fragment A、B、C 中没有单独的设置。它们仅包含一个描述其名称的 textView。
活动.kt
@Composable
fun MainScreen() {
var selectedTabIndex by remember { mutableStateOf(0) }
Column(Modifier.fillMaxSize()) {
TabRow(
selectedTabIndex = selectedTabIndex,
backgroundColor = Color.Gray,
) {
tabs.forEachIndexed { index, title ->
Tab(
text = {
Text(
text = title,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
},
selected = selectedTabIndex == index,
onClick = {
selectedTabIndex = index
},
selectedContentColor = Color.Black,
unselectedContentColor = Color.White
)
}
}
FragmentContainer(
modifier = Modifier.fillMaxSize(),
commit = getCommitFunction(
index = selectedTabIndex
)
)
}
}
private fun getFragment(index: Int): Fragment {
return when (index) {
0 -> FragmentA.newInstance()
1 -> FragmentB.newInstance()
else -> FragmentC.newInstance()
}
}
private fun getCommitFunction(
index: Int,
): FragmentTransaction.(containerId: Int) -> Unit =
{ containerId ->
showPage(this, index, containerId)
}
private fun showPage(transaction: FragmentTransaction, position: Int, containerId: Int) {
// hide current showing fragment
tabs.forEach { fragmentTag ->
val fragment: Fragment? = supportFragmentManager.findFragmentByTag(fragmentTag)
if (fragment != null && fragment.isVisible) {
transaction.hide(fragment)
}
}
val fragmentTag = tabs[position]
var fragment: Fragment? = supportFragmentManager.findFragmentByTag(fragmentTag)
if (fragment == null) {
// we don't have the fragment yet, need to create it
fragment = getFragment(position)
println("containerId $containerId")
transaction.add(containerId, fragment, fragmentTag)
} else {
println("containerId else $containerId")
// we already created the fragment, just need to show it
transaction.show(fragment)
}
transaction.setPrimaryNavigationFragment(fragment)
}
FragmentContainer.kt
@Composable
fun FragmentContainer(
modifier: Modifier = Modifier,
commit: FragmentTransaction.(containerId: Int) -> Unit
) {
val localView = LocalView.current
// Find the parent fragment, if one exists. This will let us ensure that
// fragments inflated via a FragmentContainerView are properly nested
// (which, in turn, allows the fragments to properly save/restore their state)
val parentFragment = remember(localView) {
try {
localView.findFragment<Fragment>()
} catch (e: IllegalStateException) {
// findFragment throws if no parent fragment is found
null
}
}
val containerId by rememberSaveable { mutableStateOf(View.generateViewId()) }
val container = remember { mutableStateOf<FragmentContainerView?>(null) }
val viewBlock: (Context) -> View = remember(localView) {
{ context ->
FragmentContainerView(context).apply { id = containerId }
}
}
AndroidView(
modifier = modifier,
factory = viewBlock,
update = {view ->
val fragmentManager = parentFragment?.childFragmentManager
?: (view.context as? FragmentActivity)?.supportFragmentManager
fragmentManager?.commit { commit(view.id) }
container.value = view as FragmentContainerView
}
)
// Set up a DisposableEffect that will clean up fragments when the FragmentContainer is disposed
val localContext = LocalContext.current
DisposableEffect(localView, localContext, container) {
onDispose {
val fragmentManager = parentFragment?.childFragmentManager
?: (localContext as? FragmentActivity)?.supportFragmentManager
// Now find the fragment inflated via the FragmentContainerView
val existingFragment = fragmentManager?.findFragmentById(container.value?.id ?: 0)
if (existingFragment != null && !fragmentManager.isStateSaved) {
// If the state isn't saved, that means that some state change
// has removed this Composable from the hierarchy
fragmentManager.commit(true) {
remove(existingFragment)
}
}
}
}
}
状态没有恢复的原因是没有任何东西存储它的状态。每次应用程序被终止和恢复时,它都会重新创建。
FragmentContainer(
modifier = Modifier.fillMaxSize(),
commit = getCommitFunction(
index = selectedTabIndex
)
)
我们需要一些东西来保持这些片段的状态。一种方法是使用 NavHost 并通过 Navigator 管理导航。
我在https://github.com/elye/demo_android_jetpack_compose_fragment_navigation中创建了一个简单的示例。请参阅选项卡上的最后一个设计示例。希望这有帮助。