Enter, exit and screen transitions Pro
An enter/exit transition animates an element as it appears and disappears. The tricky
part in UI Toolkit is display: an element must be display: flex before it can
animate in, and should become display: none only after it has animated out, or it keeps
taking space and catching clicks.
Cascade Pro's Show and Hide handle that order for you.
using Cascade;
panel.Show(Transition.SlideFade(Edge.Bottom, 0.35f)); // display: flex, then animate in
panel.Hide(Transition.ScaleFade(0.25f)); // animate out, then display: none
Built-in transitions
| Transition | Looks like |
|---|---|
Transition.Fade(d) | opacity only |
Transition.Slide(edge, d) | moves in from an edge |
Transition.SlideFade(edge, d) | moves and fades; the usual choice for panels and toasts |
Transition.Scale(d) | grows from 85% |
Transition.ScaleFade(d) | grows and fades; the usual choice for dialogs |
Transition.Crossfade(d) | a fade, used for swapping screens |
Add .WithEase(...) to any of them, for example Transition.ScaleFade(0.28f).WithEase(Ease.OutBack).
Toast: slide in, dismiss itself
void ShowToast()
{
toast.StopAnimations(); // a second click restarts it cleanly
toast.Show(Transition.SlideFade(Edge.Top, 0.3f).WithEase(Ease.OutCubic));
toast.schedule.Execute(HideToast).ExecuteLater(1900);
}
void HideToast()
{
if (toast.resolvedStyle.display == DisplayStyle.None) return;
toast.Hide(Transition.SlideFade(Edge.Top, 0.25f).WithEase(Ease.InCubic));
}
Ease out on the way in and ease in on the way out. Accelerating away reads as "dismissed".
Modal dialog with a dimmed backdrop
void OpenModal()
{
modalOpen = true;
modalRoot.style.display = DisplayStyle.Flex;
backdrop.Show(Transition.Fade(0.2f));
dialog.Show(Transition.ScaleFade(0.28f).WithEase(Ease.OutBack));
}
void CloseModal()
{
modalOpen = false;
backdrop.Hide(Transition.Fade(0.18f));
dialog.Hide(Transition.ScaleFade(0.2f));
// hide the container after the children finish, unless the modal was re-opened meanwhile
modalRoot.schedule.Execute(() => { if (!modalOpen) modalRoot.style.display = DisplayStyle.None; })
.ExecuteLater(240);
}
Keep the backdrop on a plain fade and give the overshoot to the dialog, so only one thing draws the eye.
Swap screens
screens.SwapTo(settingsScreen, Transition.Crossfade(0.3f));
SwapTo animates the current child of screens out (ending at
display: none) and the new one in. Both screens must already be children of
screens.
Tabs with a sliding underline
void SwitchTab(int i)
{
if (i == current) return; // clicking the open tab does nothing
pages[current].Hide(Transition.Fade(0.16f)); // out a little faster than in
pages[i].Show(Transition.Fade(0.22f));
indicator.Animate().MoveX(tabs[i].layout.x, 0.28f).Ease(Ease.OutCubic);
indicator.Animate().Width(tabs[i].layout.width, 0.28f).Ease(Ease.OutCubic);
current = i;
}
Read layout only after the first layout pass, for example in a
GeometryChangedEvent callback. Before that it returns zeros.
Show/Hide or AnimateIn/AnimateOut?
AnimateIn and AnimateOut play the same transitions but don't touch
display. Use them when you manage visibility yourself. Anything that opens and closes
repeatedly should use Show and Hide: an element left at
display: none by a previous Hide stays invisible under AnimateIn.
With Cascade Lite
Lite has no Show/Hide, but the same effect takes a few lines:
// in
panel.style.display = DisplayStyle.Flex;
panel.Animate().SlideIn(Edge.Bottom, 0.35f).Ease(Ease.OutCubic).Fade(1f, 0.35f).From(0f);
// out
panel.Animate().Fade(0f, 0.25f).Ease(Ease.InCubic)
.OnSettled(done => { if (done) panel.style.display = DisplayStyle.None; });
// "done" is false when a new animation replaced this one, e.g. the panel was opened again