diff --git a/demo/Ursa.Demo/Pages/NavMenuDemo.axaml.cs b/demo/Ursa.Demo/Pages/NavMenuDemo.axaml.cs index 6e78ad8..ec9ec24 100644 --- a/demo/Ursa.Demo/Pages/NavMenuDemo.axaml.cs +++ b/demo/Ursa.Demo/Pages/NavMenuDemo.axaml.cs @@ -1,11 +1,22 @@ using Avalonia.Controls; +using Avalonia.Interactivity; +using Ursa.Controls; namespace Ursa.Demo.Pages; public partial class NavMenuDemo : UserControl { + private readonly WHAnimationHelper _animationHelper; + public NavMenuDemo() { InitializeComponent(); + _animationHelper = new WHAnimationHelper(menu, NavMenu.IsHorizontalCollapsedProperty); + } + + protected override void OnLoaded(RoutedEventArgs e) + { + base.OnLoaded(e); + _animationHelper.Start(); } } \ No newline at end of file diff --git a/src/Ursa/Controls/NavMenu/WHAnimationHelper.cs b/src/Ursa/Controls/NavMenu/WHAnimationHelper.cs new file mode 100644 index 0000000..649a8d6 --- /dev/null +++ b/src/Ursa/Controls/NavMenu/WHAnimationHelper.cs @@ -0,0 +1,78 @@ +using Avalonia; +using Avalonia.Animation; +using Avalonia.Animation.Easings; +using Avalonia.Controls; +using Avalonia.Layout; +using Avalonia.Styling; +using Avalonia.Threading; +using Avalonia.VisualTree; + +namespace Ursa.Controls; + +public class WHAnimationHelper(Control control, AvaloniaProperty property) +{ + private CancellationTokenSource? _cancellationTokenSource; + + ~WHAnimationHelper() + { + _cancellationTokenSource?.Dispose(); + } + + public void Stop() + { + control.PropertyChanged -= AnimationTargetOnPropertyChanged; + } + + public void Start() + { + control.PropertyChanged += AnimationTargetOnPropertyChanged; + } + + private void AnimationTargetOnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e) + { + if (sender as Control != control || + e.Property != property || + control.IsLoaded is false || + control.IsVisible is false) return; + _cancellationTokenSource?.Cancel(); + _cancellationTokenSource?.Dispose(); + _cancellationTokenSource = new CancellationTokenSource(); + + var oldValue = control.DesiredSize; + control.UpdateLayout(); + var newValue = control.DesiredSize; + newValue = newValue.WithWidth(newValue.Width + 20); + control.InvalidateArrange(); + var animation = CreateAnimation(oldValue, newValue); + animation.RunAsync(control, _cancellationTokenSource.Token); + } + + protected virtual Animation CreateAnimation(Size oldValue, Size newValue) + { + return new Animation + { + Duration = TimeSpan.FromMilliseconds(300), + Easing = new CubicEaseInOut(), + FillMode = FillMode.None, + Children = + { + new KeyFrame + { + Cue = new Cue(0.0), + Setters = + { + new Setter(Layoutable.WidthProperty, oldValue.Width) + } + }, + new KeyFrame + { + Cue = new Cue(1.0), + Setters = + { + new Setter(Layoutable.WidthProperty, newValue.Width) + } + } + } + }; + } +} \ No newline at end of file