I am new to Kotlin multiplatform projects and am currently working on implementing a navigation controller using Decomposable architecture (android & iOS). The following process I have structured is based on the documentation, but unfortunately found a key limitation. That is, when a new component is pushed/bringToFont in navigation stack, it calls all previous components of child stack multiple times, and and then navigates the desired component at last. This inefficiency significantly impacts UI navigation speed. I am seeking a solution to properly structure navigation in multiplatform project.
class Screen_1_Component(
componentContext: ComponentContext,
val onClickGo: ()->Unit,
) {}
class Screen1View(val component: Screen_1_Component) {
@Composable fun loadView(){
Button(content = { Text("Go To Screen 2") }, onClick = { component.onClickGo() })
}
}
class Screen_2_Component(
componentContext: ComponentContext,
val onClickBack: ()->Unit,
) {}
class Screen2View(val component: Screen_2_Component) {
@Composable fun loadView(){
Button(content = { Text("Back To Screen 1") }, onClick = { component.onClickBack() })
}
}
class Root_Component(componentContext: ComponentContext): ComponentContext by componentContext {
private val navigation = StackNavigation<_Configuration>()
val childStack = childStack(
source = navigation,
serializer = _Configuration.serializer(),
initialConfiguration = _Configuration.Screen1,
handleBackButton = true,
childFactory = ::createChild
)
@OptIn(ExperimentalDecomposeApi::class)
private fun createChild(config: _Configuration, context: ComponentContext): _Child {
return when(config) {
is _Configuration.Screen1 -> _Child.Screen1(
Screen_1_Component(context, onClickGo = {
navigation.bringToFront(_Configuration.Screen2)
})
)
is _Configuration.Screen2 -> _Child.Screen2(
Screen_2_Component(context, onClickBack = {
navigation.pop()
})
)
}
}
sealed class _Child {
data class Screen1(val component: Screen_1_Component): _Child()
data class Screen2(val component: Screen_2_Component): _Child()
}
@Serializable sealed class _Configuration {
@Serializable data object Screen1: _Configuration()
@Serializable data object Screen2: _Configuration()
}
@Composable fun showView() {
val childStack by childStack.subscribeAsState()
Children(
stack = childStack,
animation = stackAnimation(slide())
) { child ->
when(val instance = child.instance) {
is Root_Component._Child.Screen1 -> {
Screen1View(instance.component).loadView()
}
is Root_Component._Child.Screen2 -> {
Screen2View(instance.component).loadView()
}
}
}
}
}