Animate your UI elements with smooth transitions. Supports animating numbers, colors, and sequential animations.
Function Signature
pub fn use_animation<Animated: AnimatedValue>(
run: impl 'static + FnMut(&mut AnimConfiguration) -> Animated,
) -> UseAnimation<Animated>
Parameters
run
impl FnMut(&mut AnimConfiguration) -> Animated
required
A closure that receives an AnimConfiguration for setup and returns an animated value (e.g., AnimNum, AnimColor, or tuples of animated values).
Return Type
Returns a UseAnimation<Animated> which provides methods to control the animation and access its current value.
Supported Animation Types
AnimNum: Animate numeric values (f32, f64)
AnimColor: Animate colors with smooth transitions
AnimSequential: Run multiple animations in sequence
- Tuples: Animate multiple values simultaneously (up to 12 values)
- Custom: Implement
AnimatedValue trait for custom types
Basic Usage
use freya::prelude::*;
use freya::animation::*;
fn app() -> impl IntoElement {
let mut animation = use_animation(|conf| {
conf.on_creation(OnCreation::Run);
AnimNum::new(0., 100.).time(500)
});
let width = animation.get().value();
rect()
.width(Size::px(width))
.height(Size::px(100.))
.background(Color::BLUE)
}
Animation Configuration
on_creation - Initial behavior
Control what happens when the animation is created:
let animation = use_animation(|conf| {
conf.on_creation(OnCreation::Run); // Start immediately
// conf.on_creation(OnCreation::Finish); // Jump to end
// conf.on_creation(OnCreation::Nothing); // Do nothing (default)
AnimNum::new(0., 100.).time(500)
});
on_finish - Loop behavior
Control what happens when the animation completes:
let animation = use_animation(|conf| {
conf.on_finish(OnFinish::reverse()); // Reverse direction
// conf.on_finish(OnFinish::reverse_with_delay(Duration::from_millis(500)));
// conf.on_finish(OnFinish::restart()); // Restart from beginning
// conf.on_finish(OnFinish::restart_with_delay(Duration::from_millis(500)));
// conf.on_finish(OnFinish::nothing()); // Stop (default)
AnimNum::new(0., 100.).time(500)
});
on_change - Dependency behavior
Control what happens when dependencies change:
let animation = use_animation(|conf| {
conf.on_change(OnChange::Rerun); // Rerun the animation
// conf.on_change(OnChange::Reset); // Reset to initial state (default)
// conf.on_change(OnChange::Finish); // Jump to final state
// conf.on_change(OnChange::Nothing); // Do nothing
AnimNum::new(0., 100.).time(500)
});
Controlling Animations
Start and reverse
let mut animation = use_animation(|_| AnimNum::new(0., 100.).time(500));
// Start the animation forward
animation.start();
// Start the animation in reverse
animation.reverse();
Reset and finish
let mut animation = use_animation(|_| AnimNum::new(0., 100.).time(500));
// Reset to initial state
animation.reset();
// Jump to final state
animation.finish();
Check animation status
let animation = use_animation(|_| AnimNum::new(0., 100.).time(500));
let is_running = animation.is_running();
let has_started = animation.has_run_yet();
let direction = animation.direction(); // Forward or Reverse
Examples
Animating width
use freya::prelude::*;
use freya::animation::*;
fn app() -> impl IntoElement {
let mut animation = use_animation(|_| AnimNum::new(0., 100.).time(400));
let width = animation.get().value();
rect()
.child(
Button::new()
.on_press(move |_| animation.start())
.child("Start")
)
.child(
rect()
.width(Size::px(width))
.height(Size::px(50.))
.background(Color::BLUE)
)
}
Animating colors
use freya::prelude::*;
use freya::animation::*;
fn app() -> impl IntoElement {
let mut animation = use_animation(|_| {
AnimColor::new(Color::RED, Color::BLUE).time(500)
});
let color = animation.get().value();
rect()
.background(color)
.expanded()
.child(
Button::new()
.on_press(move |_| animation.start())
.child("Animate")
)
}
Multiple animations
use freya::prelude::*;
use freya::animation::*;
fn app() -> impl IntoElement {
let mut animation = use_animation(|conf| {
conf.on_creation(OnCreation::Run);
(
AnimNum::new(0., 100.).time(500),
AnimColor::new(Color::RED, Color::BLUE).time(500),
)
});
let (width, color) = animation.get().value();
rect()
.width(Size::px(width))
.height(Size::px(100.))
.background(color)
}
Infinite loop animation
use freya::prelude::*;
use freya::animation::*;
fn app() -> impl IntoElement {
let animation = use_animation(|conf| {
conf.on_creation(OnCreation::Run);
conf.on_finish(OnFinish::reverse()); // Loop back and forth
AnimNum::new(0., 100.).time(1000)
});
let width = animation.get().value();
rect()
.width(Size::px(width))
.height(Size::px(100.))
.background(Color::BLUE)
}
Sequential animations
use freya::prelude::*;
use freya::animation::*;
fn app() -> impl IntoElement {
let mut animation = use_animation(|_| {
AnimSequential::new()
.add(AnimNum::new(0., 100.).time(300))
.add(AnimNum::new(100., 200.).time(300))
.add(AnimNum::new(200., 0.).time(300))
});
rect()
}
Reactive animations with dependencies
use freya::prelude::*;
use freya::animation::*;
fn app() -> impl IntoElement {
let target = use_state(|| 100.);
// Animation reruns when target changes
let animation = use_animation(move |conf| {
conf.on_change(OnChange::Rerun);
AnimNum::new(0., target()).time(500)
});
let width = animation.get().value();
rect()
.width(Size::px(width))
.height(Size::px(100.))
.background(Color::BLUE)
}
Transition animations
use freya::prelude::*;
use freya::animation::*;
fn app() -> impl IntoElement {
let mut color = use_state(|| Color::RED);
// Automatically animates from previous to current color
let animation = use_animation_transition(
color,
|from: Color, to| AnimColor::new(from, to).time(500)
);
rect()
.background(&*animation.read())
.expanded()
.child(
Button::new()
.on_press(move |_| color.set(Color::BLUE))
.child("Change Color")
)
}
Easing Functions
Control the animation timing curve:
use freya::animation::*;
let animation = use_animation(|_| {
AnimNum::new(0., 100.)
.time(500)
.ease(Ease::Out) // Start fast, end slow (default)
// .ease(Ease::In) // Start slow, end fast
// .ease(Ease::InOut) // Slow at both ends
});
use_animation_with_dependencies: Pass explicit dependencies instead of reactive tracking
use_animation_transition: Automatically animate between old and new values
When to Use
Use use_animation for:
- Smooth UI transitions
- Visual feedback
- Loading indicators
- Hover effects
- Page transitions
- Animations run on the main thread and request redraws automatically
- Keep animations under 1 second for best user experience
- Avoid animating too many elements simultaneously
- Use
on_finish(OnFinish::nothing()) to stop animations when not needed
Common Patterns
Pulse effect
let animation = use_animation(|conf| {
conf.on_creation(OnCreation::Run);
conf.on_finish(OnFinish::reverse());
AnimNum::new(1.0, 1.2).time(800)
});
Fade in on mount
let animation = use_animation(|conf| {
conf.on_creation(OnCreation::Run);
AnimNum::new(0.0, 1.0).time(300)
});
Slide in from left
let animation = use_animation(|conf| {
conf.on_creation(OnCreation::Run);
AnimNum::new(-100., 0.).time(400)
});