Back stack¶
Implements a simple linear history:
- The last element at the end of the stack is considered "active".
- All other elements are considered stashed.
- Children associated with stashed elements are off the screen but kept alive (see how the counter values reflect this on the video)
The back stack can never be empty – it always contains at least one element.
The back stack also supports different back press and operation strategies (see further down below).
States¶
enum class State {
CREATED, ACTIVE, STASHED, DESTROYED,
}
Visualisation of states¶
Check out the apps in our Coding challenges – they have an embedded visualisation of what happens to all the elements inside the back stack (look at the row of orange boxes below the logo).
Constructing the back stack¶
As the back stack can never be empty, it's required to define an initial target.
class BackStack<NavTarget : Any>(
initialElement: NavTarget,
savedStateMap: SavedStateMap?,
// Optional parameters are omitted
)
Default on screen resolution¶
As a default, only the active element is considered on screen.
object BackStackOnScreenResolver : OnScreenStateResolver<State> {
override fun isOnScreen(state: State): Boolean =
when (state) {
State.CREATED,
State.STASHED,
State.DESTROYED -> false
State.ACTIVE -> true
}
}
Default transition handlers¶
BackStackFader¶
rememberBackstackFader()
Adds simple cross-fading transitions
BackStackSlider¶
rememberBackstackSlider()
Adds horizontal sliding transitions so that the ACTIVE
element is in the center; other states are animated from / to the left or the right edge of the screen.
Operations¶
Push¶
backStack.push(navTarget)
Effect on stack:
[A, B, C] + Push(D) = [A, B, C, D]
Transitions the active element ACTIVE
-> STASHED
.
Adds a new element at the end of the stack with a CREATED
-> ACTIVE
transition.
Replace¶
backStack.replace(navTarget)
Effect on stack:
[A, B, C] + Replace(D) = [A, B, D]
Transitions the active element ACTIVE
-> DESTROYED
, which will be removed when the transition finishes.
Adds a new element at the end of the stack with a CREATED
-> ACTIVE
transition.
Pop¶
backStack.pop(navTarget)
Effect on stack:
[A, B, C] + Pop = [A, B]
Transitions the active element ACTIVE
-> DESTROYED
, which will be removed when the transition finishes.
Transitions the last stashed element STASHED
-> ACTIVE
.
Single top¶
backStack.singleTop(navTarget)
Effect on stack: depends on the contents of the stack:
[A, B, C, D] + SingleTop(B) = [A, B] // of same type and equals, acts as n * Pop
[A, B, C, D] + SingleTop(B') = [A, B'] // of same type but not equals, acts as n * Pop + Replace
[A, B, C, D] + SingleTop(E) = [A, B, C, D, E] // not found, acts as Push
Back press strategy¶
You can override the default strategy in the constructor. You're not limited to using the provided classes, feel free to implement your own.
class BackStack<NavTarget : Any>(
/* ... */
backPressHandler: BackPressHandlerStrategy<NavTarget, State> = PopBackPressHandler(),
/* ... */
)
PopBackPressHandler¶
The default back press handling strategy. Runs a Pop
operation.
DontHandleBackPress¶
Serves as a no-op.
Operation strategy¶
You can override the default strategy in the constructor. You're not limited to using the provided classes, feel free to implement your own.
class BackStack<NavTarget : Any>(
/* ... */
operationStrategy: OperationStrategy<NavTarget, State> = ExecuteImmediately(),
/* ... */
)
ExecuteImmediately¶
The default strategy. New operations are executed without any questions, regardless of any already running transitions.
FinishTransitionsOnNewOperation¶
All running transitions are abruptly finished when a new one is started
QueueOperations¶
The new operation is queued and executed after the current one finishes
IgnoreIfThereAreUnfinishedTransitions¶
Runs the new one only if there are no transitions happening currently; ignore and discard it otherwise