Animation guide¶
This guide presents an end-to-end workflow for adding animations to a multi-widget screen. It builds on the Animation concept page for the model and the Add an animation task for the single-widget recipe. Read both pages first.
What this guide builds¶
A small settings screen with three animated parts:
- A panel that fades in when shown and fades out when hidden.
- A list of toggle rows, each with a hover-driven background tint.
- A confirm button at the bottom that animates colour and scale on hover.
Each animated part demonstrates a different driver: panel
visibility (via BoolWhileTrue / BoolWhileFalse) for the
fade, and the built-in Enter / Leave hover transitions for the
rows and the button.
Step 1: panel show and hide animation¶
BeginPanel returns true while the panel is visible or animating
out (Hiding). Open a PushAnimate scope inside the body to drive
the slide-and-fade against the panel's visibility:
if (ui.BeginPanel("settings", screenRect, new PanelConfig
{
Hidden = true,
BackdropColor = new Color(0, 0, 0, 0.5f),
}))
{
var ctx = ui.PushAnimate("settings_anim")
.Init().Color().Set(Color.clear).Done()
.BoolWhileTrue("shown", ui.IsPanelVisible("settings"))
.Color().Blend(Color.clear, panelColor, 0.25f)
.Done()
.BoolWhileFalse("hidden", ui.IsPanelVisible("settings"))
.Color().Blend(panelColor, Color.clear, 0.25f)
.Done()
.Apply();
// ... centred body, can use ctx.GetColor() for the panel chrome ...
ui.PopAnimate();
ui.EndPanel();
}
// Show with ShowModal (not ShowPanel) to block input below.
if (m_userOpenedSettings)
ui.ShowModal("settings");
Calling HidePanel("settings") flips IsPanelVisible to false,
which transitions the context to its fade-out blend. The panel
spends one frame in Hiding (its body still runs, but it no longer
accepts input) and then EndPanel moves it to Hidden. The
BoolWhileFalse blend continues to evaluate on the frames the panel
is shown again, so the fade reads correctly the next time the panel
opens; the framework does not hold the panel open for the blend's
full duration.
For the visibility state machine, refer to Panels and modals.
Step 2: per-row hover animation inside a loop¶
Each row in the toggle list needs its own animation context.
PushID(row.Id) per iteration scopes the context's ID so each
row's state stays separate:
foreach (var row in m_settings.Rows)
{
ui.PushID(row.Id);
using (ui.Auto().Top(48))
{
var ctx = ui.PushAnimate("row_anim")
.Init().Color().Set(rowRest).Done()
.Enter().Color().Blend(rowRest, rowHover, 0.15f).Done()
.Leave().Color().Blend(rowHover, rowRest, 0.15f).Done()
.Apply();
ui.FillRounded(ctx.GetColor(), 4);
ui.Text(row.Label, "roboto_mono", 14, textColor,
TextAlign.MiddleLeft);
if (ui.Button("toggle"))
row.Value = !row.Value;
ui.PopAnimate();
}
ui.PopID();
}
PushID ensures each row's "row_anim" context is keyed by a
distinct combined ID. Without it, every row would share one
context.
For the identity model, refer to IDs.
Step 3: hover feedback on the confirm button¶
The confirm button animates colour and scale together on hover.
.Enter() and .Leave() are driven by the widget's hover state,
and .Apply() pushes the animated scale automatically, so the
content drawn before PopAnimate is already scaled:
using (ui.Auto().Bottom(48).PadHorizontal(20))
{
var ctx = ui.PushAnimate("confirm")
.Init().Color().Set(buttonRest).Scale().Set(1.0f).Done()
.Enter().Color().Blend(buttonRest, buttonHover, 0.15f)
.Scale().Blend(1.0f, 1.03f, 0.15f).Done()
.Leave().Color().Blend(buttonHover, buttonRest, 0.15f)
.Scale().Blend(1.03f, 1.0f, 0.15f).Done()
.Apply();
ui.FillRounded(ctx.GetColor(), 5);
ui.Text("Apply", "roboto_mono", 14, Color.white,
TextAlign.MiddleCenter);
if (ui.Button("apply"))
ApplySettings();
ui.PopAnimate();
}
Performance budget¶
Each PushAnimate context allocates an entry on the animation
stack and reads its values per frame. The cost is small per
context but multiplies across a list of dozens of animated rows.
Two optimisations:
- Share a single context across visually identical widgets when possible, instead of opening one per row.
- Disable animation per-row when the row is off-screen (a scroll view culls these naturally; a long flat list does not).
For the broader profiling workflow, refer to the Performance guide.
Additional resources¶
- Animation concept: the model behind the fluent API.
- Add an animation: the single-widget recipe.
- Show a modal: pairs naturally with panel show-and-hide animations.
- Stacks: the animation stack contract this guide leans on.