Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Transitions

A transition eases a property to each new value over a fixed time, with an easing curve. It is declared on the value itself, with .transition(..).

Declaring one

extern crate guido;
use guido::prelude::*;
fn main() {
let value = Color::WHITE;
let timing = TimingFunction::EaseOut;
let duration_ms = 200.0;
let _: Animated<Color> =
value.transition(Transition::new(duration_ms, timing))
;
}
  • duration_ms - Animation duration in milliseconds
  • timing - Easing curve for the animation

A bare number is the short form: .transition(200.0) is 200ms eased out.

Examples

Background Animation

extern crate guido;
use guido::prelude::*;
fn main() {
container()
    .background(Color::rgb(0.3, 0.5, 0.8).transition(200.0))
    .when_hovered(|s| s.lighter(0.15))
;
}

Border and Outline Animation

A border is declared as a pair and each half carries its own timing. Its width takes room inside the box, so a width that animates moves the content with it; a hover ring is an outline, which takes none, and whose three halves animate the same way:

extern crate guido;
use guido::prelude::*;
fn main() {
container()
    .border(1.0, Color::rgb(0.3, 0.3, 0.4).transition(150.0))
    .outline(2.0, Color::TRANSPARENT.transition(150.0), 2.0)
    .when_hovered(|s| s
        .border(1.0, Color::rgb(0.5, 0.5, 0.6))
        .outline(2.0, Color::rgb(0.5, 0.5, 0.6), 2.0))
;
}

Transform Animation

extern crate guido;
use guido::prelude::*;
fn main() {
container()
    .scale(Scale::NONE.transition(Transition::new(300.0, TimingFunction::EaseOut)))
    .when_pressed(|s| s.scale(0.98))
;
}

The resting value is what the property is when no state layer overrides it — here Scale::NONE, the size the press shrinks away from.

Duration Guidelines

DurationUse Case
100-150msQuick feedback (button press)
150-200msState changes (hover)
200-300msContent changes (expand/collapse)
300-500msMajor transitions (page changes)

Combining with State Layers

A state layer supplies a value for a property somebody else declared, and carries no timing of its own. The property eases whatever supplies its value:

extern crate guido;
use guido::prelude::*;
const FLAT: Shadow = Shadow::none();
const LOW: Shadow = Shadow::simple((0.0, 1.0), 3.0, Color::rgba(0.0, 0.0, 0.0, 0.12));
const RAISED: Shadow = Shadow::simple((0.0, 3.0), 6.0, Color::rgba(0.0, 0.0, 0.0, 0.19));
fn main() {
container()
    .background(Color::rgb(0.2, 0.2, 0.3).transition(200.0))
    .shadow(LOW.transition(200.0))

    // State changes trigger the animations declared above
    .when_hovered(|s| s.lighter(0.1).shadow(RAISED))
    .when_pressed(|s| s.darker(0.05).shadow(FLAT))
;
}

Writing a timing on the override does not compile — it would be a declaration that is legal and does nothing:

// not compiled: the line is the mistake the paragraph above names.
.when_hovered(|s| s.background(HOT.transition(900.0)))   // error

Complete Example

extern crate guido;
use guido::prelude::*;
const LOW: Shadow = Shadow::simple((0.0, 1.0), 3.0, Color::rgba(0.0, 0.0, 0.0, 0.12));
const RAISED: Shadow = Shadow::simple((0.0, 3.0), 6.0, Color::rgba(0.0, 0.0, 0.0, 0.19));
const HIGH: Shadow = Shadow::simple((0.0, 6.0), 10.0, Color::rgba(0.0, 0.0, 0.0, 0.22));
fn animated_card() -> Container {
    container()
        .padding(20.0)
        .background(Color::rgb(0.15, 0.15, 0.2).transition(200.0))
        .corners(12.0)
        .border(1.0, Color::rgb(0.25, 0.25, 0.3))
        .outline(2.0, Color::TRANSPARENT.transition(150.0), 2.0)
        .shadow(RAISED.transition(250.0))

        // State layers
        .when_hovered(|s| s
            .lighter(0.05)
            .outline(2.0, Color::rgb(0.4, 0.6, 0.9), 2.0)
            .shadow(HIGH)
        )
        .when_pressed(|s| s
            .darker(0.02)
            .shadow(LOW)
        )

        .child(container().child(text("Hover me!").color(Color::WHITE)))
}
fn main() {}

API Reference

/// Ease to each new value this holds
value.transition(transition: impl Into<TransitionConfig>) -> Animated<T>;

/// A bare number is milliseconds, eased out
Transition::new(duration_ms: f32, timing: TimingFunction) -> Transition;

/// Create a spring-based transition
Transition::spring(config: SpringConfig) -> Transition