feat:Implements subtle animations for the NavMenu in a non-intrusive way.
This commit is contained in:
@@ -1,11 +1,22 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using Ursa.Controls;
|
||||||
|
|
||||||
namespace Ursa.Demo.Pages;
|
namespace Ursa.Demo.Pages;
|
||||||
|
|
||||||
public partial class NavMenuDemo : UserControl
|
public partial class NavMenuDemo : UserControl
|
||||||
{
|
{
|
||||||
|
private readonly WHAnimationHelper _animationHelper;
|
||||||
|
|
||||||
public NavMenuDemo()
|
public NavMenuDemo()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
_animationHelper = new WHAnimationHelper(menu, NavMenu.IsHorizontalCollapsedProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnLoaded(RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnLoaded(e);
|
||||||
|
_animationHelper.Start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
78
src/Ursa/Controls/NavMenu/WHAnimationHelper.cs
Normal file
78
src/Ursa/Controls/NavMenu/WHAnimationHelper.cs
Normal file
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user