Skip to main content

Aggregate View Transitions

Transitions control how a NavController changes its current screen. Hosanna provides three transition types:

  • Simple: switch immediately.
  • Fade: fade to a color, swap the screen, then fade back.
  • Slide: slide forward on push/replace and backward on pop/reset.

Configure named transitions

Put transition definitions under controls.NavController.transition:

{
"controls": {
"NavController": {
"transition": {
"default": {
"transitionType": "Fade",
"transitionOptions": {
"duration": 300,
"color": "#000000"
}
},
"slide": {
"transitionType": "Slide",
"transitionOptions": {
"duration": 280,
"parallax": 0.3
}
},
"none": {
"transitionType": "Simple"
}
}
}
}
}

Fade options:

OptionDefaultMeaning
color#000000Overlay color.
duration1000Total fade-in/out duration in milliseconds.

Slide options:

OptionDefaultMeaning
duration300Duration in milliseconds.
parallax0.3Outgoing-view shift as a fraction of slide width.
widthowner width, then 1920Optional explicit slide distance.

Select a transition

Tab selection and NavController stack transitions have separate owners, with Simple, Fade, and Slide converging on the same screen lifecycle completionTab selection and NavController stack transitions have separate owners, with Simple, Fade, and Slide converging on the same screen lifecycle completion

Set a default on one controller:

NavController({
id: 'mainNav',
initialView: HomeScreen({ id: 'home' }),
transitionStyleKey: 'controls.NavController.transition.slide',
})

Or override one operation on the mounted controller:

this.getSubView<NavControllerView>('mainNav')?.push(
DetailsScreen({ id: 'details' }),
true,
'controls.NavController.transition.slide',
);

All primary stack operations accept the optional key:

push(view, animated = true, key?)
pop(animated = true, key?)
reset(endIndex = 0, newFirstScreen?, animated = false, key?)
replace(newView?, animated = false, key?)

The resolution order is:

  1. the per-operation key;
  2. the controller's transitionStyleKey;
  3. controls.NavController.transition.default;
  4. Hosanna's internal fade fallback if no configured transition can be built.

Passing animated: false still runs the transition lifecycle, but swaps views without the visual animation.

Tabs

TabController does not animate tab selection. A tab definition's transitionStyleKey is assigned to that tab's child NavController, so it affects pushes and pops within the tab.

Lifecycle and custom transitions

An AggregateViewTransition receives the owner, source, target, animation flag, and removal policy through execute(). A custom subclass implements begin() and must eventually call finish(). The base finish() finalizes the current view, lifecycle callbacks, hibernation policy, and focus.

If a transition allocates overlay renderers or timers, release or stop them before delegating to super.finish(). Keep the target's final view state in sync with any renderer values changed per frame.

Navigation operations are ignored while the current transition is in Started or InProgress, so prevent repeated action dispatch at the UI level.

Talk to us