Skip to main content
Avalonia provides a powerful animation system that allows you to create smooth, performant animations for any property. The animation system is built on a flexible architecture that supports keyframe animations, property transitions, and custom animators.

Animation Architecture

The animation system consists of several key components:
  • Animatable: Base class for all objects that can be animated
  • Animation: Defines keyframe-based animations
  • Transitions: Automatically animate property changes
  • Animators: Execute the interpolation between values
  • Easing Functions: Control the rate of change over time

Keyframe Animations

Keyframe animations allow you to define specific values at specific points in time. The animation system interpolates between these keyframes.

Basic Animation

<Border>
    <Border.Styles>
        <Style Selector="Border">
            <Style.Animations>
                <Animation Duration="0:0:2" IterationCount="Infinite">
                    <KeyFrame Cue="0%">
                        <Setter Property="Opacity" Value="0.0"/>
                    </KeyFrame>
                    <KeyFrame Cue="100%">
                        <Setter Property="Opacity" Value="1.0"/>
                    </KeyFrame>
                </Animation>
            </Style.Animations>
        </Style>
    </Border.Styles>
</Border>

Animation Properties

From ~/workspace/source/src/Avalonia.Base/Animation/Animation.cs:
PropertyTypeDescription
DurationTimeSpanThe active time of the animation
IterationCountIterationCountNumber of times to repeat (supports Infinite)
PlaybackDirectionPlaybackDirectionNormal, Reverse, Alternate, AlternateReverse
FillModeFillModeHow values are applied before/after animation
EasingEasingEasing function (default: LinearEasing)
DelayTimeSpanInitial delay before animation starts
DelayBetweenIterationsTimeSpanDelay between iteration repeats
SpeedRatiodoubleSpeed multiplier (default: 1.0)

KeyFrame Timing

Keyframes can be specified using either cues (percentage) or absolute time:
<!-- Using Cue (percentage-based) -->
<KeyFrame Cue="0%">
    <Setter Property="Width" Value="100"/>
</KeyFrame>
<KeyFrame Cue="50%">
    <Setter Property="Width" Value="200"/>
</KeyFrame>
<KeyFrame Cue="100%">
    <Setter Property="Width" Value="100"/>
</KeyFrame>

<!-- Using KeyTime (absolute time) -->
<Animation Duration="0:0:4">
    <KeyFrame KeyTime="0:0:0">
        <Setter Property="Height" Value="50"/>
    </KeyFrame>
    <KeyFrame KeyTime="0:0:2">
        <Setter Property="Height" Value="150"/>
    </KeyFrame>
</Animation>
You cannot mix Cue and KeyTime in the same KeyFrame. Choose one timing mode and use it consistently.

KeySpline for Custom Timing

Use KeySpline to define cubic bezier curves for per-keyframe easing:
<KeyFrame Cue="50%" KeySpline="0.25,0.1,0.25,1.0">
    <Setter Property="Opacity" Value="0.5"/>
</KeyFrame>

Property Transitions

Transitions automatically animate property changes. They’re simpler than keyframe animations but very effective for interactive UI.

Defining Transitions

<Border>
    <Border.Transitions>
        <Transitions>
            <DoubleTransition Property="Opacity" Duration="0:0:0.3"/>
            <ThicknessTransition Property="Margin" Duration="0:0:0.2"/>
            <BrushTransition Property="Background" Duration="0:0:0.4"/>
        </Transitions>
    </Border.Transitions>
</Border>

Available Transition Types

From ~/workspace/source/src/Avalonia.Base/Animation/Transitions/:
  • DoubleTransition - For double properties
  • FloatTransition - For float properties
  • IntegerTransition - For int properties
  • BoolTransition - For bool properties
  • ColorTransition - For Color properties
  • BrushTransition - For IBrush properties
  • PointTransition - For Point properties
  • SizeTransition - For Size properties
  • ThicknessTransition - For Thickness properties
  • CornerRadiusTransition - For CornerRadius properties
  • VectorTransition - For Vector properties
  • BoxShadowsTransition - For BoxShadows properties
  • TransformOperationsTransition - For transform operations
  • Rotate3DTransition - For 3D rotations

Transition with Easing

public class MyControl : UserControl
{
    public MyControl()
    {
        Transitions = new Transitions
        {
            new DoubleTransition
            {
                Property = OpacityProperty,
                Duration = TimeSpan.FromSeconds(0.3),
                Easing = new CubicEaseOut()
            }
        };
    }
}

Easing Functions

Easing functions control the rate of change during an animation. Avalonia includes 30+ built-in easing functions.

Built-in Easings

From ~/workspace/source/src/Avalonia.Base/Animation/Easings/: Linear
  • LinearEasing - Constant speed
Quadratic
  • QuadraticEaseIn, QuadraticEaseOut, QuadraticEaseInOut
Cubic
  • CubicEaseIn, CubicEaseOut, CubicEaseInOut
Quartic
  • QuarticEaseIn, QuarticEaseOut, QuarticEaseInOut
Quintic
  • QuinticEaseIn, QuinticEaseOut, QuinticEaseInOut
Sine
  • SineEaseIn, SineEaseOut, SineEaseInOut
Exponential
  • ExponentialEaseIn, ExponentialEaseOut, ExponentialEaseInOut
Circular
  • CircularEaseIn, CircularEaseOut, CircularEaseInOut
Back
  • BackEaseIn, BackEaseOut, BackEaseInOut
Elastic
  • ElasticEaseIn, ElasticEaseOut, ElasticEaseInOut
Bounce
  • BounceEaseIn, BounceEaseOut, BounceEaseInOut
Advanced
  • SplineEasing - Custom cubic bezier curve
  • SpringEasing - Physics-based spring animation

Using Easings in XAML

<DoubleTransition Property="Width" Duration="0:0:0.5">
    <DoubleTransition.Easing>
        <CubicEaseOut/>
    </DoubleTransition.Easing>
</DoubleTransition>

Custom Spline Easing

<DoubleTransition Property="Height" Duration="0:0:0.4">
    <DoubleTransition.Easing>
        <SplineEasing ControlPointX1="0.42" ControlPointY1="0.0" 
                      ControlPointX2="0.58" ControlPointY2="1.0"/>
    </DoubleTransition.Easing>
</DoubleTransition>

Spring Easing

<DoubleTransition Property="ScaleX" Duration="0:0:1">
    <DoubleTransition.Easing>
        <SpringEasing Mass="1" Stiffness="100" Damping="10"/>
    </DoubleTransition.Easing>
</DoubleTransition>

Programmatic Animation

Running Animations from Code

using Avalonia.Animation;
using Avalonia.Animation.Easings;

public async Task AnimateButton()
{
    var animation = new Animation
    {
        Duration = TimeSpan.FromSeconds(1),
        Easing = new CubicEaseInOut(),
        Children =
        {
            new KeyFrame
            {
                Cue = new Cue(0),
                Setters =
                {
                    new Setter(OpacityProperty, 1.0),
                    new Setter(ScaleTransform.ScaleXProperty, 1.0)
                }
            },
            new KeyFrame
            {
                Cue = new Cue(1),
                Setters =
                {
                    new Setter(OpacityProperty, 0.0),
                    new Setter(ScaleTransform.ScaleXProperty, 1.5)
                }
            }
        }
    };

    await animation.RunAsync(myButton);
}

Cancellable Animations

private CancellationTokenSource? _animationCts;

public async Task StartAnimation()
{
    _animationCts?.Cancel();
    _animationCts = new CancellationTokenSource();

    try
    {
        await animation.RunAsync(control, _animationCts.Token);
    }
    catch (OperationCanceledException)
    {
        // Animation was cancelled
    }
}

public void StopAnimation()
{
    _animationCts?.Cancel();
}
Use await animation.RunAsync() for one-time animations that need to complete. For continuous animations, set IterationCount to IterationCount.Infinite and use Apply() instead.

Controlling Animation Lifecycle

var subscription = animation.Apply(
    control,
    clock: null,
    match: Observable.Return(true),
    onComplete: () => Console.WriteLine("Animation completed")
);

// Later: stop the animation
subscription.Dispose();

Page Transitions

Page transitions animate content changes in navigation scenarios.

CrossFade Transition

<TransitioningContentControl>
    <TransitioningContentControl.PageTransition>
        <CrossFade Duration="0:0:0.3"/>
    </TransitioningContentControl.PageTransition>
</TransitioningContentControl>

PageSlide Transition

<TransitioningContentControl>
    <TransitioningContentControl.PageTransition>
        <PageSlide Duration="0:0:0.5" Orientation="Horizontal"/>
    </TransitioningContentControl.PageTransition>
</TransitioningContentControl>

Composite Page Transition

<TransitioningContentControl>
    <TransitioningContentControl.PageTransition>
        <CompositePageTransition>
            <CrossFade Duration="0:0:0.2"/>
            <PageSlide Duration="0:0:0.3" Orientation="Horizontal"/>
        </CompositePageTransition>
    </TransitioningContentControl.PageTransition>
</TransitioningContentControl>

Animation Best Practices

Performance Optimization

Animate GPU-accelerated properties for best performance:
  • Opacity
  • TranslateTransform (X, Y)
  • RotateTransform (Angle)
  • ScaleTransform (ScaleX, ScaleY)
These properties can be animated without triggering layout or re-rendering of parent controls.
Avoid animating these properties as they can cause performance issues:
  • Width / Height - Triggers layout on every frame
  • Margin - Affects parent layout
  • FontSize - Requires text re-rendering
Instead, use ScaleTransform to achieve similar visual effects.

Transition Lifecycle

From ~/workspace/source/src/Avalonia.Base/Animation/Animatable.cs, transitions are automatically:
  • Enabled when a control is added to the visual tree
  • Disabled when a control is removed from the visual tree
This prevents unnecessary animations on controls that aren’t visible.

Memory Management

// Store animation subscriptions and dispose when done
private readonly CompositeDisposable _animationDisposables = new();

public void StartAnimations()
{
    _animationDisposables.Add(animation1.Apply(control1, ...));
    _animationDisposables.Add(animation2.Apply(control2, ...));
}

protected override void OnDetachedFromVisualTree()
{
    _animationDisposables.Dispose();
    base.OnDetachedFromVisualTree();
}

Advanced Animation Techniques

Custom Animators

Create custom animators for types not supported out of the box:
using Avalonia.Animation.Animators;

public class CustomTypeAnimator : Animator<CustomType>
{
    public override CustomType Interpolate(double progress, CustomType oldValue, CustomType newValue)
    {
        // Implement custom interpolation logic
        return new CustomType(
            oldValue.Value + (newValue.Value - oldValue.Value) * progress
        );
    }
}

FillMode Behavior

Control how animated values are applied before and after the animation:
  • None - Property reverts to base value before and after
  • Forward - Final animated value persists after animation
  • Backward - Initial animated value applies during delay
  • Both - Both Forward and Backward behaviors
<Animation Duration="0:0:2" FillMode="Both" Delay="0:0:1">
    <KeyFrame Cue="0%">
        <Setter Property="Opacity" Value="0"/>
    </KeyFrame>
    <KeyFrame Cue="100%">
        <Setter Property="Opacity" Value="1"/>
    </KeyFrame>
</Animation>

PlaybackDirection Options

<!-- Normal: 0% → 100% -->
<Animation PlaybackDirection="Normal" IterationCount="3"/>

<!-- Reverse: 100% → 0% -->
<Animation PlaybackDirection="Reverse" IterationCount="3"/>

<!-- Alternate: 0% → 100% → 0% → 100% -->
<Animation PlaybackDirection="Alternate" IterationCount="4"/>

<!-- AlternateReverse: 100% → 0% → 100% → 0% -->
<Animation PlaybackDirection="AlternateReverse" IterationCount="4"/>

See Also

Build docs developers (and LLMs) love