This page was machine-translated from Portuguese and may contain errors. The Portuguese version is canonical.
How to create a continuous pulse (loop)
Purpose. Make something pulse/blink indefinitely (a “loading” indicator, glow, the breathing of a button). LoopAnimation cycles a value from 0 → 1 repeatedly, with or without easing, without onComplete (it is infinite — you stop it with stop()).
APIs used
new LoopAnimation(float duration [, float fps, boolean easeInOut])— each cycle lastsdurationseconds and restarts on its own.fpsdefault 60;easeInOutdefaultfalse(linear). WitheaseInOut=true, it applies cubic ease-in-out per cycle.LoopAnimation.onUpdate(Runnable)— callback on each frame; readgetValue()(0–1, progress of the current cycle).LoopAnimation.getValue()— current progress of the cycle.LoopAnimation.start()/stop()— starts / stops the loop. There is noonCompleteorcancel()— it is infinite by nature.Component.alpha(float)— applies opacity (for the “breathing” effect).Component.repaint()— static; required inonUpdate.
Full example (copy, paste and run)
package com.exemplo;
import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.animation.*;
/** Runnable main screen: pulses a "●" in a loop; stop the loop when the screen closes. */
public class MainWindow extends Window
{
private LoopAnimation pulse;
@Override
public void onShow() throws Exception
{
super.onShow();
setLayout(new VerticalLayout());
Label dot = new Label("●");
add(dot);
// 1 s cycle, 60 fps, with easing (smooth pulse)
pulse = new LoopAnimation(1f, 60f, true);
pulse.onUpdate(() ->
{
// value goes 0 → 1 and restarts; maps to opacity 0.3 → 1.0
float v = 0.3f + 0.7f * pulse.getValue();
dot.alpha(v);
Component.repaint();
})
.start();
// button that ends the pulse (e.g. when loading finishes)
add(new Button("Parar").onAction(e -> pulse.stop()));
}
@Override
public void onRemove()
{
// Stop it when leaving the screen so you don't leave an orphan loop animating off-screen.
if (pulse != null) pulse.stop();
super.onRemove();
}
}
The snippet below shows only the core. To run it, place it inside the
MainWindowskeleton above.
Minimal snippet
// verified in the source: LoopAnimation(duration, fps, easeInOut); no onComplete; stop with stop()
Label dot = new Label("●");
add(dot);
// 1 s cycle, 60 fps, with easing (smooth pulse)
LoopAnimation pulse = new LoopAnimation(1f, 60f, true);
pulse.onUpdate(() ->
{
// value goes 0 → 1 and restarts; maps to opacity 0.3 → 1.0
float v = 0.3f + 0.7f * pulse.getValue();
dot.alpha(v);
Component.repaint();
})
.start();
// later, to end the pulse (e.g. when loading finishes):
pulse.stop();
Important cautions:
- Keep the reference (
pulse) so you can callstop(). ALoopAnimationwithoutstop()runs forever and continuously consumes CPU/GPU (each frame callsrepaint()). - Stop when leaving the screen: call
pulse.stop()when theWindowis closed (onRemove/hide) so you don’t leave an orphan loop animating off-screen. getValue()returns to 0 at the start of each cycle. For a “back-and-forth” pulse (0→1→0), map it with a triangular or sine function overgetValue().
Dig deeper
- Value animations · Press and feedback
- Sibling recipe: Fade a component · Move a component
Was this page helpful?Thanks for the feedback!