Navigation with Child Stack¶
The StackNavigator¶
All navigation in Child Stack
is performed using the StackNavigator
interface, which is extended by the StackNavigation
interface.
StackNavigator
contains the navigate
method with the following arguments:
transformer
- converts the current stack of configurations to a new one. The stack is represented asList
, where the last element is the top of the stack, and the first element is the bottom of the stack.onComplete
- called when navigation is finished.
There is also navigate
extension function without the onComplete
callback, for convenience.
Warning
The configuration stack returned by the transformer
function must not be empty.
// In your component class
val navigation = StackNavigation<Configuration>()
The navigation process¶
During the navigation process, the Child Stack
navigation model compares the new stack of configurations with the previous one. It ensures that all removed components are destroyed, and that there is only one component resumed at a time - the top one. All components in the back stack are always either stopped or destroyed.
The Child Stack
navigation model usually performs the navigation synchronously, which means that by the time the navigate
method returns, the navigation is finished and all component lifecycles are moved into required states. However, the navigation is performed asynchronously in case of recursive invocations - e.g. pop
is called from onResume
lifecycle callback of a component being pushed. All recursive invocations are queued and performed one by one once the current navigation is finished.
StackNavigator extension functions¶
There are StackNavigator
extension functions to simplify the navigation. Some of which were already used in the Child Stack Overview example.
push(configuration)¶
Pushes the provided Configuration
at the top of the stack. Decompose will throw an exception if the provided Configuration
is already present in the stack. This usually happens when a component is pushed on user interaction (e.g. a button click). Consider using pushNew instead.
Illustration
[A, B*]
navigation.push(Configuration.C)
[A, B, C*]
pushNew(configuration)¶
Pushes the provided Configuration
at the top of the stack. Does nothing if the provided Configuration
is already on top of the stack. Decompose will throw an exception if the provided Configuration
is already present in the back stack (not at the top of the stack).
This can be useful when pushing a component on button click, to avoid pushing the same component if the user clicks the same button quickly multiple times.
Illustration 1
[A, B*]
navigation.pushNew(Configuration.C)
[A, B, C*]
Illustration 2
[A, B, C*]
navigation.pushNew(Configuration.C)
[A, B, C*]
pushToFront(configuration)¶
Pushes the provided configuration to the top of the stack, removing the configuration from the back stack, if any.
This API works similar to bringToFront
, except it compares configurations by equality rather than by configuration class.
Illustration 1
[A(1), B(1)*]
navigation.pushToFront(Configuration.A(2))
[A(1), B(1), A(2)*]
Illustration 2
[A(1), B(1), A(2)]
navigation.pushToFront(Configuration.A(1))
[B(1), A(2), A(1)*]
Illustration 3
[A(1), B(1), A(2)]
navigation.pushToFront(Configuration.A(2))
[A(1), B(1), A(2)*]
pop¶
Pops the latest configuration at the top of the stack.
Illustration
[A, B, C*]
navigation.pop()
// Or
navigation.pop { isSuccess ->
// Called when the navigation is finished.
// isSuccess - `true` if the stack size was greater than 1 and a component was popped, `false` otherwise.
}
[A, B*]
popWhile(predicate)¶
Pops configurations at the top of the stack while the provided predicate returns true.
Illustration
[A, B, C, D*]
navigation.popWhile { topOfStack: Configuration -> topOfStack !is B }
[A, B*]
popTo(index)¶
Pops configurations at the top of the stack so that the provided index becomes active (the new top of the stack).
Illustration
[A, B, C, D*]
navigation.popTo(index = 1)
[A, B*]
popToFirst¶
Pops configurations at the top of the stack so that the first configuration becomes active (the new top of the stack).
Illustration
[A, B, C, D*]
navigation.popToFirst()
[A*]
replaceCurrent(configuration)¶
Replaces the current configuration at the top of the stack with the provided Configuration
.
Illustration
[A, B, C*]
navigation.replaceCurrent(Configuration.D)
[A, B, D*]
replaceAll(vararg configurations)¶
Replaces all configurations currently in the stack with the provided configurations. Components that remain in the stack are not recreated, components that are no longer in the stack are destroyed.
Illustration
[A, B, C*]
navigation.replaceAll(Configuration.B, Configuration.C, Configuration.D)
[B, C, D*]
bringToFront(configuration)¶
Removes all components with configurations of the provided Configuration
's class, and adds the provided Configuration
to the top of the stack. This is primarily helpful when implementing a Decompose app with Bottom Navigation. See the related discussion in the old repository.
Note
The operation is performed as one transaction. If there is already a component with the same configuration, it will not be recreated.
Illustration
[A, B, C*]
navigation.bringToFront(Configuration.B)
[A, C, B*]