Class Transition
float property: the toolkit's reusable "CSS transition".
A widget owns a Transition per property it wants to animate (opacity,
a fill level, a lerp factor, a position, …), configures it once, then just
moves the target with to(float); value(), read each paint,
eases toward it.
Like a CSS transition, the developer controls whether it animates
(enabled), the duration, the easing curve and
whether it repeats, for any property, since the value is just a
number the widget maps onto whatever it draws.
Reduced motion: while the user has asked the system for less motion
(SystemPreferences.reduceMotion()), to jumps as a disabled
transition does, so every animation built on this class honours it without a line.
Optimized: it drives itself off the scene's frame ticker only while
moving and unregisters the instant it settles, so an idle widget costs nothing.
Safe: to / snap(float) are UI-thread-confined, and when the
owner has no scene (headless, or detached) it simply jumps to the target: the
same "final state, no animation" a test or an off-screen widget wants. A repeating
one, which has no final state, starts once its owner is painted in a scene.
private final Transition fade = new Transition(this).duration(0.15).easing(Easing.EASE_OUT);
// on state change:
fade.to(visible ? 1 : 0);
// in onPaint:
color.timesAlpha(fade.value());
-
Constructor Summary
ConstructorsConstructorDescriptionTransition(Widget<?> owner) A transition starting (and resting) at0.Transition(Widget<?> owner, float initial) A transition starting atinitial, repaintingowneras it runs. -
Method Summary
Modifier and TypeMethodDescriptionNarrows what each frame of this animation repaints, for an animation that moves a small part of a large widget.doubleduration()Duration of one run, in seconds.duration(double seconds) Sets the animation length in seconds (0= no animation;tosnaps).Sets the timing curve (defaultEasing.EASE_OUT).enabled(boolean value) Whenfalse,tojumps instead of animating (defaulttrue).booleanWhether the value is still moving: false once it has settled on its target.booleanWhether animating at all; when off, the value jumps to its target.repeat(boolean value) Whentrue, the animation ping-pongs between its endpoints forever (a pulse/breathe) untilsnap(float)orrepeat(false)stops it.booleanrepeats()Whether the transition restarts on completion instead of settling.sceneTime(boolean value) Whether this transition runs on the scene's scene time (and so obeysScene.setPaused(boolean)andScene.setTimeScale(double)) instead of wall time.voidsnap(float value) Jumps tovalueimmediately, cancelling any animation.floattarget()voidto(float target) Animates the value towardtarget.floatvalue()
-
Constructor Details
-
Transition
A transition starting (and resting) at0. -
Transition
A transition starting atinitial, repaintingowneras it runs.
-
-
Method Details
-
duration
Sets the animation length in seconds (0= no animation;tosnaps). -
damages
Narrows what each frame of this animation repaints, for an animation that moves a small part of a large widget.By default a running transition calls
owner.invalidate()once per frame, which is the whole widget — right for a button, whose animation is the button, and badly wrong for a list, whose focus ring is one row of many. Measured: a list arriving at focus repainted itself whole for eleven consecutive frames so that one row's outline could fade in. Under a full-frame default that costs nothing, because the frame was full anyway; under a partial one it is the difference between a row and a list.The first choice is still to give the animation an owner that is what moves — a tab strip rather than the tabbed pane. This is for when no such widget exists because the moving part is drawn by the parent itself.
The callback must invalidate something, and enough: it is the only repaint the frame gets, so a region short of what the animation draws leaves stale pixels behind, which no assertion can see. It runs on the UI thread, once per animated frame, and must not change layout.
- Parameters:
region- invalidates the part this animation draws, ornullfor the owner- Returns:
- this
-
easing
Sets the timing curve (defaultEasing.EASE_OUT). -
enabled
Whenfalse,tojumps instead of animating (defaulttrue). -
repeat
Whentrue, the animation ping-pongs between its endpoints forever (a pulse/breathe) untilsnap(float)orrepeat(false)stops it. -
sceneTime
Whether this transition runs on the scene's scene time (and so obeysScene.setPaused(boolean)andScene.setTimeScale(double)) instead of wall time. Defaultfalse.The default is what every widget in the toolkit wants: a hover, focus or press fade is shell feedback, and feedback that stops responding while an app pauses its own animation reads as a hang, not as a pause. Turn it on for a transition that animates content (a game object's position, a value the simulation owns), which is exactly what pausing is supposed to stop.
Read when the transition registers itself with the scene, so flipping it mid-animation takes effect on the next run rather than the current one.
-
duration
public double duration()Duration of one run, in seconds. -
isEnabled
public boolean isEnabled()Whether animating at all; when off, the value jumps to its target. -
repeats
public boolean repeats()Whether the transition restarts on completion instead of settling. -
to
public void to(float target) Animates the value towardtarget. Jumps immediately (no animation) when disabled, zero-duration, the owner is detached from a scene, or the user asked the system for less motion (Motion.reduced()). UI thread.A
repeatingtransition asked for while its owner is in no scene does not jump, because a pulse has no final state to jump to: it waits where it is and starts the first time its owner is painted in a scene. -
snap
public void snap(float value) Jumps tovalueimmediately, cancelling any animation. UI thread. -
value
public float value()- Returns:
- the current (eased) value; read this each paint
-
target
public float target()- Returns:
- the value it is heading toward
-
isAnimating
public boolean isAnimating()Whether the value is still moving: false once it has settled on its target.
-