Child Panels overview¶
The Child Panels¶
Child Panels
is a navigation model for managing a set of up to three child components (panels): Main (required), Details (optional) and Extra (optional). This navigation model can be compared with Compose List-Details Layout.
Warning
This navigation model is experimental since version 3.2.0-beta01
, the API is subject to change.
Similarly to Child Stack
, each component has its own Lifecycle
automatically controlled by the navigation model depending on the current ChildPanelsMode
.
It is possible to have more than one Child Panels
navigation model in a component, nested navigation is also supported.
The Child Panels
navigation model consists of the following main entities:
- Panels - represents a state of the
Child Panels
navigation model. The navigation is performed by creating a new navigation state from the previous one.Panels#main
- a configuration of the Main panel.Panels#details
- an optional configuration of the Details panel, default value isnull
.Panels#extra
- an optional configuration of the Extra panel, default value isnull
.Panels#mode
- the currentChildPanelsMode
, determines how lifecycles of the panels within the Child Panels navigation model are changing, default value isChildPanelsMode.SINGLE
.
- ChildPanels - a simple data class that stores all child components (panels) and their configurations, as well as the current mode.
ChildPanels#main
- a Main child component.ChildPanels#details
- an optional Details child component.ChildPanels#extra
- an optional Extra child component.ChildPanels#mode
- the currentChildPanelsMode
.
- ChildPanelsMode - determines how lifecycles of the child components (panels) within the
Child Panels
navigation model are changing. SINGLE
- there is only oneRESUMED
panel at a time. If the Extra panel exists, then it isRESUMED
and all other panels areCREATED
. Otherwise, if the Details panel exists, then it isRESUMED
and the Main panel isCREATED
. Otherwise, the Main panel isRESUMED
.DUAL
- there are at most two panelsRESUMED
at a time. The Main panel is alwaysRESUMED
. If the Extra panel exists, then it isRESUMED
and the Details panel (if exists) isCREATED
. Otherwise, if the Details panel exists, then it isRESUMED
.TRIPLE
- any existing panel is alwaysRESUMED
.- PanelsNavigation - an interface that accepts navigation commands and forwards them to all subscribed observers.
Component Configurations¶
Similarly to Child Stack
, each component created and managed by the Child Panels
has a configuration, please read the documentation about child configurations.
Initializing Child Panels¶
There are three steps to initialize Child Panels
:
- Create a new instance of
PanelsNavigation
and assign it to a variable or a property. - Initialize the
Child Panels
navigation model using theComponentContext#childPanels
extension function and passPanelsNavigation
into it along with other arguments. - The
childPanels
function returnsValue<ChildPanels>
that can be observed in the UI. Assign the returnedValue
to another property or a variable.
Displaying panels with Compose¶
Child Panels
state can be observed and displayed in Compose by using the ChildPanels
Composable
function from the experimental Compose extensions module provided by Decompose. Please see the related documentation for more information.
Example¶
Here is a very basic example of a list-details navigation:
import com.arkivanov.decompose.ComponentContext
interface MainComponent
class DefaultMainComponent(
componentContext: ComponentContext,
onItemSelected: (id: Long) -> Unit,
) : MainComponent, ComponentContext by componentContext
interface DetailsComponent
class DefaultDetailsComponent(
componentContext: ComponentContext,
itemId: Long,
onFinished: () -> Unit,
) : DetailsComponent, ComponentContext by componentContext
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.router.panels.ChildPanels
import com.arkivanov.decompose.router.panels.ChildPanelsMode
import com.arkivanov.decompose.router.panels.Panels
import com.arkivanov.decompose.router.panels.PanelsNavigation
import com.arkivanov.decompose.router.panels.activateDetails
import com.arkivanov.decompose.router.panels.childPanels
import com.arkivanov.decompose.router.panels.dismissDetails
import com.arkivanov.decompose.router.panels.setMode
import com.arkivanov.decompose.value.Value
import kotlinx.serialization.Serializable
import kotlinx.serialization.builtins.serializer
interface PanelsComponent {
val panels: Value<ChildPanels<*, MainComponent, *, DetailsComponent, Nothing, Nothing>>
fun setMode(mode: ChildPanelsMode)
}
class DefaultPanelsComponent(
componentContext: ComponentContext,
) : PanelsComponent, ComponentContext by componentContext {
private val nav = PanelsNavigation<Unit, DetailsConfig, Nothing>()
override val panels: Value<ChildPanels<*, MainComponent, *, DetailsComponent, Nothing, Nothing>> =
childPanels(
source = nav,
serializers = Unit.serializer() to DetailsConfig.serializer(),
initialPanels = { Panels(main = Unit) },
handleBackButton = true,
mainFactory = { _, ctx ->
DefaultMainComponent(
componentContext = ctx,
onItemSelected = { nav.activateDetails(details = DetailsConfig(itemId = it)) },
)
},
detailsFactory = { cfg, ctx ->
DefaultDetailsComponent(
componentContext = ctx,
itemId = cfg.itemId,
onFinished = nav::dismissDetails,
)
},
)
override fun setMode(mode: ChildPanelsMode) {
nav.setMode(mode)
}
@Serializable
private data class DetailsConfig(val itemId: Long)
}
Screen recreation and process death on (not only) Android¶
Child Panels
automatically preserves the state when a configuration change or process death occurs. To disable state preservation completely, pass serializers = null
argument. When navigation state saving is disabled, the state is reset to the initial value when recreated.
Components are created in their order. I.e. the Main component is created first, then the Details component is created (if exists), and lastly the Extra component is created (if exists). Components are destroyed in reverse order.
Multiple Child Panels in a component¶
When multiple Child Panels
are used in one component, each such Child Panels
must have a unique key
argument associated. The keys are required to be unique only within the hosting component, so it is ok for different components to have Child Panels
with same keys. An exception will be thrown if multiple Child Panels
with the same key are detected in a component.