AnimationRx.Wpf
2.0.2
dotnet add package AnimationRx.Wpf --version 2.0.2
NuGet\Install-Package AnimationRx.Wpf -Version 2.0.2
<PackageReference Include="AnimationRx.Wpf" Version="2.0.2" />
<PackageVersion Include="AnimationRx.Wpf" Version="2.0.2" />
<PackageReference Include="AnimationRx.Wpf" />
paket add AnimationRx.Wpf --version 2.0.2
#r "nuget: AnimationRx.Wpf, 2.0.2"
#:package AnimationRx.Wpf@2.0.2
#addin nuget:?package=AnimationRx.Wpf&version=2.0.2
#tool nuget:?package=AnimationRx.Wpf&version=2.0.2
AnimationRx.Wpf
AnimationRx.Avalonia
AnimationRx
Reactive, composable animation primitives for WPF and Avalonia. Extends ReactiveUI for Schedulers and Rx conventions.
AnimationRx exposes animations as IObservable<Unit> (for effects that complete) and value streams like IObservable<double> (for interpolated values). This makes animations easy to compose, sequence, run in parallel, cancel (dispose), and bind to reactive view-models.
- AnimationRx.Wpf: targets .NET Framework
4.6.2,4.7.2,4.8and.NET 8/9/10 (windows). - AnimationRx.Avalonia: targets
.NET 8/9/10.
Cancellation model: every animation is an
IObservable. Dispose the subscription returned bySubscribe()to cancel mid-flight.
Packages
AnimationRx.Wpf
NuGet:
- Package:
AnimationRx.Wpf
Package Manager:
Install-Package AnimationRx.Wpf
AnimationRx.Avalonia
NuGet:
- Package:
AnimationRx.Avalonia
Package Manager:
Install-Package AnimationRx.Avalonia
Quick start
WPF
using CP.AnimationRx;
using System.Reactive.Disposables;
// Fade in over 300ms using Sine ease
var d = someElement
.OpacityTo(300, 1.0, Ease.SineInOut)
.Subscribe();
// later => cancel if needed
// d.Dispose();
Avalonia
using CP.AnimationRx;
// Fade out over 250ms
someVisual
.OpacityTo(250, 0.0, Ease.SineOut)
.Subscribe();
Core concepts
Duration
Animations are driven by a Duration value stream, where:
Duration.Percentis always in[0..1]DurationPercentage(...)produces the progress streamEaseAnimation(...)reshapes the progress curveDistance(...)maps progress into a delta (e.g., pixels, degrees)
Easing
Easing is provided by:
Easeenum (selects common easings)Easesextension methods (e.g.,BackIn,SineOut) onIObservable<Duration>
Threading & schedulers
Both libraries separate:
- time source (defaults to
RxSchedulers.TaskpoolScheduler) - UI updates (defaults to
RxSchedulers.MainThreadScheduler)
All built-in UI animations marshal reads/writes to the UI thread.
API reference
In the sections below:
rx<T>meansIObservable<T>- methods returning
rx<Unit>represent animations that complete
AnimationRx.Wpf API
Namespace: CP.AnimationRx
Setup
Add these usings:
using CP.AnimationRx;
using System.Reactive;
using System.Reactive.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
Frames & timing (WPF)
Animations.AnimateFrame(double framesPerSecond, IScheduler? scheduler = null) → rx<long>
Emits an increasing tick at approximately the requested FPS.
var frames = Animations.AnimateFrame(60)
.Subscribe(i => Debug.WriteLine($"tick {i}"));
Animations.AnimateFrame(TimeSpan period, IScheduler? scheduler = null) → rx<long>
Emits ticks on a fixed period.
var frames = Animations.AnimateFrame(TimeSpan.FromMilliseconds(33))
.Subscribe(i => Debug.WriteLine(i));
Animations.RenderFrames() → rx<long>
Emits one tick per WPF CompositionTarget.Rendering (synchronized to the UI rendering loop).
var renderLoop = Animations.RenderFrames()
.Subscribe(_ =>
{
// do per-render work here
});
Animations.MilliSecondsElapsed(IScheduler scheduler) → rx<double>
Emits elapsed milliseconds since subscription (starting with 0.0).
var ms = Animations.MilliSecondsElapsed(RxSchedulers.TaskpoolScheduler)
.Subscribe(t => Debug.WriteLine($"elapsed {t:0}ms"));
Animations.DurationPercentage(double milliSeconds, IScheduler? scheduler = null) → rx<Duration>
Produces progress from 0..1 over the duration, always emitting a final 1.0 and then completing.
Animations.DurationPercentage(500)
.Subscribe(d => Debug.WriteLine(d.Percent));
Animations.DurationPercentage(rx<double> milliSeconds, IScheduler? scheduler = null) → rx<Duration>
Same as above, but the duration can change dynamically.
var durationMs = Observable.Return(750.0);
Animations.DurationPercentage(durationMs)
.Subscribe(d => Debug.WriteLine(d.Percent));
Animations.ToDuration(this rx<double>) → rx<Duration>
Maps raw [0..1] values to Duration.
Observable.Return(0.25)
.Concat(Observable.Return(0.5))
.Concat(Observable.Return(1.0))
.ToDuration()
.Subscribe(d => Debug.WriteLine(d.Percent));
Animations.TakeOneEvery<T>(this rx<T>, TimeSpan interval, IScheduler? scheduler = null) → rx<T>
Back-pressure helper that delays each element by interval and concatenates (one “in flight” at a time).
var throttled = Observable.Range(1, 5)
.TakeOneEvery(TimeSpan.FromMilliseconds(200));
throttled.Subscribe(Console.WriteLine);
Easing (WPF)
Ease enum
Use Ease.None for linear or pick from:
BackIn, BackOut, BackInOut, BounceIn, BounceOut, BounceInOut, CircIn, CircOut, CircInOut, CubicIn, CubicOut, CubicInOut, ElasticIn, ElasticOut, ElasticInOut, ExpoIn, ExpoOut, ExpoInOut, QuadIn, QuadOut, QuadInOut, QuarticIn, QuarticOut, QuarticInOut, QuinticIn, QuinticOut, QuinticInOut, SineIn, SineOut, SineInOut.
Eases.EaseAnimation(this rx<Duration> progress, Ease ease) → rx<Duration>
Applies the selected ease to a duration stream.
Animations.DurationPercentage(400)
.EaseAnimation(Ease.ExpoOut)
.Subscribe(d => Debug.WriteLine(d.Percent));
Specific easing functions on rx<Duration>
Each method below reshapes Duration.Percent:
BackIn(),BackOut(),BackInOut()BounceIn(),BounceOut(),BounceInOut()CircIn(),CircOut(),CircInOut()CubicIn(),CubicOut(),CubicInOut()ElasticIn(),ElasticOut(),ElasticInOut()ExpoIn(),ExpoOut(),ExpoInOut()QuadIn(),QuadOut(),QuadInOut()QuarticIn(),QuarticOut(),QuarticInOut()QuinticIn(),QuinticOut(),QuinticInOut()SineIn(),SineOut(),SineInOut()
Example of using a specific easing method directly:
Animations.DurationPercentage(300)
.SineInOut()
.Subscribe(d => Debug.WriteLine(d.Percent));
Value animation (WPF)
Animations.AnimateValue(double ms, double from, double to, Ease ease = Ease.None, IScheduler? scheduler = null) → rx<double>
Creates a numeric interpolation stream from from to to.
Animations.AnimateValue(600, from: 0, to: 100, Ease.SineInOut)
.ObserveOn(RxSchedulers.MainThreadScheduler)
.Subscribe(v => viewModel.Progress = v);
Animations.Distance(this rx<Duration> progress, double distance) → rx<double>
Converts progress to progress.Percent * distance.
Animations.DurationPercentage(300)
.Distance(200) // 0..200
.Subscribe(px => Debug.WriteLine(px));
Animations.Distance(this rx<Duration> progress, rx<double> distance) → rx<double>
Same as above, but distance is dynamic.
var distance = Observable.Return(150.0);
Animations.DurationPercentage(300)
.Distance(distance)
.Subscribe(px => Debug.WriteLine(px));
Animations.PixelsPerSecond(this rx<double> milliSeconds, double velocity) → rx<double>
Converts milliseconds to pixels at a constant velocity (px/s): velocity * ms / 1000.
Animations.MilliSecondsElapsed(RxSchedulers.TaskpoolScheduler)
.PixelsPerSecond(velocity: 200)
.Subscribe(px => Debug.WriteLine($"{px:0.0}px"));
Element property animation (WPF)
All methods below return rx<Unit>.
OpacityTo(this UIElement element, double ms, double to, Ease ease = Ease.None, IScheduler? scheduler = null)
Animates UIElement.Opacity to to.
myPanel
.OpacityTo(250, 0.0, Ease.SineOut)
.Concat(myPanel.OpacityTo(250, 1.0, Ease.SineIn))
.Subscribe();
WidthTo(this FrameworkElement element, double ms, double to, Ease ease = Ease.None, IScheduler? scheduler = null)
Animates Width (falls back to ActualWidth if Width is NaN).
myControl.WidthTo(400, 320, Ease.ExpoOut).Subscribe();
HeightTo(this FrameworkElement element, double ms, double to, Ease ease = Ease.None, IScheduler? scheduler = null)
Animates Height (falls back to ActualHeight if Height is NaN).
myControl.HeightTo(400, 80, Ease.ExpoOut).Subscribe();
MarginTo(this FrameworkElement element, double ms, Thickness to, Ease ease = Ease.None, IScheduler? scheduler = null)
Animates Margin to to.
myControl.MarginTo(300, new Thickness(10), Ease.SineInOut).Subscribe();
PaddingTo(this Control element, double ms, Thickness to, Ease ease = Ease.None, IScheduler? scheduler = null)
Animates Padding to to.
myButton.PaddingTo(300, new Thickness(24, 8, 24, 8), Ease.SineOut).Subscribe();
CanvasLeftTo(this FrameworkElement element, double ms, double to, Ease ease = Ease.None, IScheduler? scheduler = null)
Animates the Canvas.Left attached property.
myItem.CanvasLeftTo(350, 120, Ease.ExpoOut).Subscribe();
CanvasTopTo(this FrameworkElement element, double ms, double to, Ease ease = Ease.None, IScheduler? scheduler = null)
Animates the Canvas.Top attached property.
myItem.CanvasTopTo(350, 40, Ease.ExpoOut).Subscribe();
BrushColorTo(this SolidColorBrush brush, double ms, Color to, Ease ease = Ease.None, IScheduler? scheduler = null)
Animates a SolidColorBrush.Color.
If the brush might be frozen, clone it first and assign a non-frozen brush instance to your element.
var brush = new SolidColorBrush(Colors.OrangeRed);
myBorder.Background = brush;
brush.BrushColorTo(500, Colors.SteelBlue, Ease.SineInOut).Subscribe();
Margin edge animation (WPF)
These helpers animate individual Thickness components per-frame.
LeftMarginMove(this FrameworkElement element, double ms, double position, Ease ease = Ease.None, IScheduler? scheduler = null)
Moves Margin.Left to an absolute position.
myControl.LeftMarginMove(400, 100, Ease.ExpoOut).Subscribe();
RightMarginMove(this FrameworkElement element, rx<double> ms, rx<double> position, Ease ease = Ease.None, IScheduler? scheduler = null)
Dynamic duration + dynamic position.
var ms = Observable.Return(250.0);
var pos = Observable.Return(30.0);
myControl.RightMarginMove(ms, pos, Ease.SineInOut).Subscribe();
TopMarginMove(this FrameworkElement element, double ms, double position, Ease ease = Ease.None)
Moves Margin.Top to position.
myControl.TopMarginMove(300, 12, Ease.SineOut).Subscribe();
BottomMarginMove(this FrameworkElement element, double ms, double position, Ease ease = Ease.None, IScheduler? scheduler = null)
Moves Margin.Bottom to position.
myControl.BottomMarginMove(300, 12, Ease.SineOut).Subscribe();
Observable overloads also exist for
LeftMarginMove,RightMarginMove,TopMarginMove,BottomMarginMovewherems,position, and/oreasecan beIObservable.
Transforms (WPF)
Transform helpers will add the required transform into RenderTransform using a TransformGroup if needed.
TranslateTransform(this FrameworkElement element, rx<double> ms, rx<Point> position, Ease xease = Ease.None, Ease yease = Ease.None)
Animates translate using dynamic duration and a dynamic target point.
var ms = Observable.Return(400.0);
var pos = Observable.Return(new Point(120, 40));
myControl.TranslateTransform(ms, pos, Ease.ExpoOut, Ease.SineIn).Subscribe();
TranslateTransform(this FrameworkElement element, double ms, double xPosition, double yPosition, Ease xease = Ease.None, Ease yease = Ease.None, IScheduler? scheduler = null)
Animates translate to (xPosition,yPosition).
myControl.TranslateTransform(400, 120, 40, Ease.ExpoOut, Ease.SineIn).Subscribe();
RotateTransform(this FrameworkElement element, double ms, double angle, Ease ease = Ease.None, IScheduler? scheduler = null)
Animates rotation by delta (angle - initialAngle internally).
myControl.RotateTransform(300, 45, Ease.SineOut).Subscribe();
ScaleTransform(this FrameworkElement element, double ms, double scaleX, double scaleY, Ease easeX = Ease.None, Ease easeY = Ease.None, IScheduler? scheduler = null)
Animates scale by delta.
myControl.ScaleTransform(250, 1.2, 1.2, Ease.SineInOut, Ease.SineInOut).Subscribe();
SkewTransform(this FrameworkElement element, double ms, double angleX, double angleY, Ease easeX = Ease.None, Ease easeY = Ease.None, IScheduler? scheduler = null)
Animates skew by delta.
myControl.SkewTransform(250, 10, 0, Ease.SineOut, Ease.SineOut).Subscribe();
Absolute transform helpers (WPF)
These are convenience helpers that animate to absolute targets:
TranslateTo(this FrameworkElement element, double ms, double toX, double toY, ...)ScaleTo(this FrameworkElement element, double ms, double toScaleX, double toScaleY, ...)RotateTo(this FrameworkElement element, double ms, double toAngle, ...)SkewTo(this FrameworkElement element, double ms, double toAngleX, double toAngleY, ...)
TranslateTo example:
myControl.TranslateTo(300, toX: 0, toY: 0, Ease.ExpoOut, Ease.ExpoOut).Subscribe();
“Effects” helpers (WPF)
ShakeTranslate(this FrameworkElement element, double ms, double amplitude, int shakes = 6, Ease ease = Ease.None, IScheduler? scheduler = null)
Shakes horizontally using TranslateTransform and returns to the original position.
myControl.ShakeTranslate(600, amplitude: 12, shakes: 8, ease: Ease.SineOut).Subscribe();
PulseOpacity(this UIElement element, double milliSecondsPerHalf, double low = 0.2, double high = 1.0, int pulses = 1, Ease ease = Ease.None, IScheduler? scheduler = null)
Pulses opacity between low and high for pulses cycles.
myControl.PulseOpacity(150, low: 0.3, high: 1.0, pulses: 3, ease: Ease.SineInOut).Subscribe();
Composition helpers (WPF)
Sequence(this IEnumerable<rx<Unit>> animations) → rx<Unit>
Concatenates animations in-order.
var anim = new[]
{
myControl.OpacityTo(150, 0.0),
myControl.OpacityTo(150, 1.0),
myControl.ScaleTransform(200, 1.1, 1.1, Ease.SineOut, Ease.SineOut),
myControl.ScaleTransform(200, 1.0, 1.0, Ease.SineIn, Ease.SineIn)
}.Sequence();
anim.Subscribe();
Parallel(this IEnumerable<rx<Unit>> animations) → rx<Unit>
Merges animations and completes when the last one finishes.
new[]
{
myControl.OpacityTo(250, 1.0, Ease.SineOut),
myControl.TranslateTransform(250, 120, 0, Ease.ExpoOut, Ease.ExpoOut)
}.Parallel().Subscribe();
RepeatAnimation(this rx<Unit> animation, int? count = null) → rx<Unit>
Repeats an animation. If count is null, repeats forever until disposed.
var pulseOnce = myControl.PulseOpacity(120, pulses: 1);
pulseOnce.RepeatAnimation(count: 5).Subscribe();
// pulseOnce.RepeatAnimation().Subscribe(); // infinite until disposed
Stagger(this IEnumerable<rx<Unit>> animations, TimeSpan staggerBy, IScheduler? scheduler = null) → IEnumerable<rx<Unit>>
Delays each animation by an incremental amount.
var items = listBox.Items.Cast<FrameworkElement>();
var anims = items.Select(el => el.TranslateTransform(300, -40, 0, Ease.SineOut, Ease.SineOut)
.Concat(el.TranslateTransform(250, 0, 0, Ease.ExpoOut, Ease.ExpoOut)));
anims.Stagger(TimeSpan.FromMilliseconds(80))
.Parallel()
.Subscribe();
AnimationRx.Avalonia API
Namespace: CP.AnimationRx
Setup
Add these usings:
using CP.AnimationRx;
using System.Reactive;
using System.Reactive.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
Frames & timing (Avalonia)
Animations.AnimateFrame(double framesPerSecond, IScheduler? scheduler = null) → rx<long>
Frames on an interval (default uses taskpool scheduler).
Animations.AnimateFrame(60)
.Subscribe(i => Debug.WriteLine(i));
Animations.AnimateFrame(TimeSpan period, IScheduler? scheduler = null) → rx<long>
Fixed-period ticker.
Animations.AnimateFrame(TimeSpan.FromMilliseconds(16))
.Subscribe(_ => { /* timer */ });
Animations.MilliSecondsElapsed(IScheduler scheduler) → rx<double>
Elapsed milliseconds since subscription.
Animations.MilliSecondsElapsed(RxSchedulers.TaskpoolScheduler)
.Subscribe(ms => Debug.WriteLine(ms));
Animations.DurationPercentage(double ms, IScheduler? scheduler = null) → rx<Duration>
Progress [0..1] over a fixed duration.
Animations.DurationPercentage(500)
.EaseAnimation(Ease.SineInOut)
.Subscribe(d => Debug.WriteLine(d.Percent));
Animations.DurationPercentage(rx<double> ms, IScheduler? scheduler = null) → rx<Duration>
Progress [0..1] over a dynamic duration.
var durationMs = Observable.Return(350.0);
Animations.DurationPercentage(durationMs)
.Subscribe(d => Debug.WriteLine(d.Percent));
Animations.TakeOneEvery<T>(this rx<T>, TimeSpan interval, IScheduler? scheduler = null) → rx<T>
Delays each element by interval and sequences them.
Observable.Range(1, 3)
.TakeOneEvery(TimeSpan.FromMilliseconds(250))
.Subscribe(Console.WriteLine);
Easing (Avalonia)
Eases.EaseAnimation(this rx<Duration> progress, Ease ease) → rx<Duration>
Applies a selected ease.
Animations.DurationPercentage(300)
.EaseAnimation(Ease.ExpoOut)
.Subscribe(d => Debug.WriteLine(d.Percent));
Eases.ToDuration(this rx<double>) → rx<Duration>
Maps raw [0..1] values to Duration.
Observable.Return(0.0)
.Concat(Observable.Return(1.0))
.ToDuration()
.Subscribe(d => Debug.WriteLine(d.Percent));
Specific easing functions on rx<Duration>
Same list as WPF (BackIn, BounceOut, SineInOut, etc.).
Animations.DurationPercentage(300)
.BounceOut()
.Subscribe(d => Debug.WriteLine(d.Percent));
Value animation (Avalonia)
Animations.AnimateValue(double ms, double from, double to, Ease ease = Ease.None, IScheduler? scheduler = null) → rx<double>
Interpolates numeric values.
Animations.AnimateValue(400, 0, 100, Ease.SineInOut)
.Subscribe(v => Debug.WriteLine(v));
Animations.Distance(this rx<Duration>, double distance) → rx<double>
Progress to delta.
Animations.DurationPercentage(200)
.Distance(50)
.Subscribe(v => Debug.WriteLine(v));
Animations.Distance(this rx<Duration>, rx<double> distance) → rx<double>
Dynamic distance.
var distance = Observable.Return(180.0);
Animations.DurationPercentage(200)
.Distance(distance)
.Subscribe(v => Debug.WriteLine(v));
Visual / control property animation (Avalonia)
All methods below return rx<Unit>.
OpacityTo(this Visual element, double ms, double to, Ease ease = Ease.None, IScheduler? scheduler = null)
Animates Visual.Opacity.
myVisual.OpacityTo(250, 0.0, Ease.SineOut).Subscribe();
WidthTo(this Control element, double ms, double to, Ease ease = Ease.None, IScheduler? scheduler = null)
Animates Control.Width (falls back to Bounds.Width if Width is NaN).
myControl.WidthTo(300, 240, Ease.ExpoOut).Subscribe();
HeightTo(this Control element, double ms, double to, Ease ease = Ease.None, IScheduler? scheduler = null)
Animates Control.Height.
myControl.HeightTo(300, 90, Ease.ExpoOut).Subscribe();
MarginTo(this Control element, double ms, Thickness to, Ease ease = Ease.None, IScheduler? scheduler = null)
Animates Control.Margin.
myControl.MarginTo(300, new Thickness(12), Ease.SineInOut).Subscribe();
PaddingTo(this TemplatedControl element, double ms, Thickness to, Ease ease = Ease.None, IScheduler? scheduler = null)
Animates TemplatedControl.Padding.
myTemplatedControl.PaddingTo(200, new Thickness(16, 8), Ease.SineOut).Subscribe();
CanvasLeftTo(this Control element, double ms, double to, Ease ease = Ease.None, IScheduler? scheduler = null)
Animates the Canvas.Left attached property.
myControl.CanvasLeftTo(250, 120, Ease.ExpoOut).Subscribe();
CanvasTopTo(this Control element, double ms, double to, Ease ease = Ease.None, IScheduler? scheduler = null)
Animates the Canvas.Top attached property.
myControl.CanvasTopTo(250, 40, Ease.ExpoOut).Subscribe();
BrushColorTo(this SolidColorBrush brush, double ms, Color to, Ease ease = Ease.None, IScheduler? scheduler = null)
Animates a SolidColorBrush.Color.
var brush = new SolidColorBrush(Colors.OrangeRed);
myBorder.Background = brush;
brush.BrushColorTo(500, Colors.SteelBlue, Ease.SineInOut).Subscribe();
ColorTo(this SolidColorBrush brush, double ms, Color to, Ease ease = Ease.None, IScheduler? scheduler = null)
Alias for BrushColorTo.
brush.ColorTo(500, Colors.LimeGreen, Ease.ExpoOut).Subscribe();
Transforms (Avalonia)
Transform helpers will add the required transform to Visual.RenderTransform using a TransformGroup if needed.
TranslateTransform(this Visual element, double ms, double xPosition, double yPosition, Ease xease = Ease.None, Ease yease = Ease.None, IScheduler? scheduler = null)
Animates translation.
myVisual.TranslateTransform(400, 120, 40, Ease.ExpoOut, Ease.SineIn).Subscribe();
TranslateTo(this Visual element, double ms, double toX, double toY, ...)
Alias for TranslateTransform.
myVisual.TranslateTo(300, 0, 0, Ease.ExpoOut, Ease.ExpoOut).Subscribe();
RotateTransform(this Visual element, double ms, double angle, Ease ease = Ease.None, IScheduler? scheduler = null)
Animates rotation to the target angle.
myVisual.RotateTransform(300, 45, Ease.SineOut).Subscribe();
RotateTo(this Visual element, double ms, double toAngle, ...)
Alias for RotateTransform.
myVisual.RotateTo(300, 0, Ease.ExpoOut).Subscribe();
ScaleTransform(this Visual element, double ms, double scaleX, double scaleY, Ease easeX = Ease.None, Ease easeY = Ease.None, IScheduler? scheduler = null)
Animates scale.
myVisual.ScaleTransform(250, 1.2, 1.2, Ease.SineInOut, Ease.SineInOut).Subscribe();
ScaleTo(this Visual element, double ms, double toScaleX, double toScaleY, ...)
Alias for ScaleTransform.
myVisual.ScaleTo(250, 1.0, 1.0, Ease.SineOut, Ease.SineOut).Subscribe();
SkewTransform(this Visual element, double ms, double angleX, double angleY, Ease easeX = Ease.None, Ease easeY = Ease.None, IScheduler? scheduler = null)
Animates skew.
myVisual.SkewTransform(250, 10, 0, Ease.SineOut, Ease.SineOut).Subscribe();
SkewTo(this Visual element, double ms, double toAngleX, double toAngleY, ...)
Alias for SkewTransform.
myVisual.SkewTo(250, 0, 0, Ease.ExpoOut, Ease.ExpoOut).Subscribe();
“Effects” helpers (Avalonia)
ShakeTranslate(this Visual element, double ms, double amplitude, int shakes = 6, Ease ease = Ease.None, IScheduler? scheduler = null)
Shakes horizontally and returns to the original position.
myVisual.ShakeTranslate(600, amplitude: 12, shakes: 8, ease: Ease.SineOut).Subscribe();
PulseOpacity(this Visual element, double milliSecondsPerHalf, double low = 0.2, double high = 1.0, int pulses = 1, Ease ease = Ease.None, IScheduler? scheduler = null)
Pulses opacity between low and high for pulses cycles.
myVisual.PulseOpacity(150, low: 0.3, high: 1.0, pulses: 3, ease: Ease.SineInOut).Subscribe();
Composition helpers (Avalonia)
Sequence(this IEnumerable<rx<Unit>> animations) → rx<Unit>
Sequences animations.
new[]
{
myVisual.OpacityTo(150, 0.0),
myVisual.OpacityTo(150, 1.0),
}.Sequence().Subscribe();
Parallel(this IEnumerable<rx<Unit>> animations) → rx<Unit>
Runs animations in parallel.
new[]
{
myVisual.OpacityTo(250, 1.0),
myVisual.TranslateTransform(250, 120, 0)
}.Parallel().Subscribe();
RepeatAnimation(this rx<Unit> animation, int? count = null) → rx<Unit>
Repeats an animation.
var pulse = myVisual.PulseOpacity(120, pulses: 1);
pulse.RepeatAnimation(5).Subscribe();
DelayBetween(this IEnumerable<rx<Unit>> animations, TimeSpan delay, IScheduler? scheduler = null) → rx<Unit>
Inserts a delay between each animation in a sequence.
new[]
{
myVisual.OpacityTo(100, 0.0),
myVisual.OpacityTo(100, 1.0),
}
.DelayBetween(TimeSpan.FromMilliseconds(200))
.Subscribe();
Stagger(this IEnumerable<rx<Unit>> animations, TimeSpan staggerBy, IScheduler? scheduler = null) → IEnumerable<rx<Unit>>
Delays each animation by an incremental stagger.
var anims = items.Select(v => v.OpacityTo(250, 1.0, Ease.SineOut));
anims.Stagger(TimeSpan.FromMilliseconds(60))
.Parallel()
.Subscribe();
Patterns & tips
- Prefer composing animations with Rx (
Concat,Merge,Sequence,Parallel) rather than timers. - Always dispose subscriptions for:
- cancellation
- preventing leaks if element lifetime is shorter than the animation
- For smooth per-frame loops you can build a
dtstream fromAnimateFrame(...)(orRenderFrames()in WPF).
License
MIT License. © Chris Pulman
AnimationRx - Empowering Automation with Reactive Technology ⚡🏭
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0-windows10.0.19041 is compatible. net9.0-windows was computed. net9.0-windows10.0.19041 is compatible. net10.0-windows was computed. net10.0-windows10.0.19041 is compatible. |
| .NET Framework | net462 is compatible. net463 was computed. net47 was computed. net471 was computed. net472 is compatible. net48 is compatible. net481 was computed. |
-
.NETFramework 4.6.2
- ReactiveUI.Wpf (>= 22.3.1)
-
.NETFramework 4.7.2
- ReactiveUI.Wpf (>= 22.3.1)
-
.NETFramework 4.8
- ReactiveUI.Wpf (>= 22.3.1)
-
net10.0-windows10.0.19041
- ReactiveUI.Wpf (>= 22.3.1)
-
net8.0-windows10.0.19041
- ReactiveUI.Wpf (>= 22.3.1)
-
net9.0-windows10.0.19041
- ReactiveUI.Wpf (>= 22.3.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Compatability with Net 8/9 and net462