Skip to main content

Aggregate View Transitions

What are Transitions?

Transitions are classes that control the switch between aggregate views (for example, pushing and popping screens in NavController, or switching tabs in TabController which internally uses a NavController). Hosanna ships with two built-ins:

  • SimpleTransition: completes immediately (no visual animation)
  • FadeTransition: fades out, swaps view, fades in again; configurable color and duration

You can specify a transition per navigation action (push/pop/reset/replace) or define defaults in style JSON, so all NavController instances use the same transition unless overridden.

Tip: Pick the Right Default

Set a sensible default in style.json (like a quick fade) and override per call only when needed. It keeps code clean and UX consistent.

Use a transition for a single push/pop (concise)

// inside a view that owns a NavController
import { NavControllerView } from 'hosanna-ui/views/aggregate-views/NavController';

// Push with a specific transition via style key (overrides default for this call)
(this.parent as NavControllerView).push(nextView, true, 'controls.NavController.transition.fadeQuickBlack');

// Pop with a specific transition
(this.parent as NavControllerView).pop(true, 'controls.NavController.transition.fade');

See the example rig (core action only):

// Inside a button click handler
const nextView = ScreenPusher({ viewIndex: this.viewIndex + 1 });
(this.parent as NavControllerView)
.push(nextView, true, this.viewIndex === 2 ? 'controls.NavController.transition.fadeQuickBlack' : undefined);

Define a default transition via style.json

You can set a default transition in your style config so every NavController uses it unless a call overrides it with a transitionStyleKey.

{
"controls": {
"NavController": {
"transition": {
"default": {
"transitionType": "Simple"
},
"fade": {
"transitionType": "Fade",
"transitionOptions": {
"duration": 500,
"color": "~theme.colors.grayscale900"
}
}
}
}
}
}
  • Key format: controls.NavController.transition.<name>; the framework also looks up controls.NavController.transition.default as a fallback.
  • Types: Fade and Simple are built-in. Map to FadeTransition or SimpleTransition respectively.
Where Keys Live

Transition keys are part of your theme config under controls.NavController.transition. Use default as a safety net for all controllers.

You can create multiple named transitions and reference them by key. For example:

{
"controls": {
"NavController": {
"transition": {
"default": { "transitionType": "Simple" },
"fade": {
"transitionType": "Fade",
"transitionOptions": { "duration": 500, "color": "~theme.colors.grayscale900" }
},
"fadeQuickBlack": {
"transitionType": "Fade",
"transitionOptions": { "duration": 250, "color": "#000000" }
},
"fadeSlowGreen": {
"transitionType": "Fade",
"transitionOptions": { "duration": 1200, "color": "#003300" }
},
"fadeSlowYellow": {
"transitionType": "Fade",
"transitionOptions": { "duration": 1200, "color": "#333300" }
}
}
}
}
}

Built-ins (reference)

  • SimpleTransition: completes instantly (no animation)
  • FadeTransition: fades to color and back; accepts color and duration options

Use either by specifying a transition style key or overriding per push/pop/reset/replace call.

Caution: Don’t Mutate State During Animation

Write the animation, then call finish(). Avoid setting view state in the middle of a tick—let the transition switch views and focus cleanly.

Defaults for FadeTransition if not provided: color: '#000000', duration: 1000 (ms).

Create your own transition (overview)

To implement a custom transition:

  • Extend AggregateViewTransition
  • Override begin() to perform the animation (and call finish() when done)
  • Optionally override finish() to finalize focus/visibility and cleanup

Keep begin() focused on: staging target view, animating in/out, switching current view, then calling finish().

See example rigs for usage patterns.

Tip: Start Simple

Prototype with SimpleTransition to confirm lifecycle and focus are correct, then swap in a custom transition.

Transition style keys and config

Transitions are declared in style.json and referenced by key. Params shape:

  • transitionType: Simple | Fade

  • transitionOptions: e.g., { duration: 500, color: '#000000' }

  • Key format: controls.NavController.transition.<name> (with default as fallback)

  • Supported types: Simple, Fade (extendable via custom transitions)

⚙️ Key Props & Concepts

Key Concepts
  • transitionStyleKey: A string key like controls.NavController.transition.fade applied on NavController or passed per call.
  • AggregateViewTransitionType: Simple | Fade. Extend via custom classes.
  • transitionOptions: For FadeTransition, supports color and duration (ms).
  • Per-call override: push(view, animated, key), pop(animated, key), reset(..., key), replace(..., key).
  • Focus management: finish() handles visibility and focus; don’t fight it.

Live Example

Try It

Use the buttons to push screens with different fade presets, then pop to see how the default applies.

Use transitions with TabController

Each TabController tab hosts its own NavController. Set a tab-specific default transition via transitionStyleKey on the tab definition. Under the hood, TabController passes this key to the child NavController.

You can override the transition per call on all primary navigation APIs:

  • push(view, animated = true, key?)
  • pop(animated = true, key?)
  • reset(endIndex = 0, newFirstScreen?, animated = false, key?)
  • replace(newView?, animated = false, key?)
Tip: Per-Tab Personality

Give each tab a different transitionStyleKey for distinct feel, while keeping navigation APIs the same.

Per-call style keys are converted internally to a temporary transition instance; if omitted, the controller's transitionStyleKey (or the default in style.json) is used.

How transition resolution works

When a navigation action occurs, the aggregate view picks a transition using:

  • A temporary per-call transition (if provided)
  • Otherwise, the configured transitionStyleKey
  • Otherwise, the fallback key controls.NavController.transition.default

Transition Flow (Sequence)

Transition Flow

Resolution Order
  1. Per-call style key → 2) Controller transitionStyleKey → 3) controls.NavController.transition.default.

Class Relationships

Transition Classes

API Surface Overview

Transition API

Internally, resolution works like this:

  • Build a temporary transition if a per-call style key is provided
  • Else build from the controller’s transitionStyleKey
  • Else build from controls.NavController.transition.default If a referenced key is missing or invalid, a warning is logged and the default is used.

Minimal custom transition

  • Extend AggregateViewTransition
  • Stage target → animate → call finish()
Caution: Clean Up Overlays

If your transition adds overlay nodes (e.g., a fade rectangle), release them in finish() to avoid leaks.