From bda626ec07ea94f9277143087d0f2179c51ca9d2 Mon Sep 17 00:00:00 2001 From: Hill23333 Date: Tue, 4 Mar 2025 22:46:30 +0800 Subject: [PATCH] feat: MyLoading --- PCL2.Neo.sln.DotSettings.user | 8 + PCL2.Neo/Animations/Easings/EasePower.cs | 10 ++ PCL2.Neo/Animations/Easings/MyBackEaseIn.cs | 20 +++ PCL2.Neo/Animations/Easings/MyBackEaseOut.cs | 20 +++ PCL2.Neo/Animations/IAnimation.cs | 12 +- PCL2.Neo/Animations/OpacityAnimation.cs | 1 + .../RotateTransformAngleAnimation.cs | 1 + .../ScaleTransformScaleXAnimation.cs | 1 + .../ScaleTransformScaleYAnimation.cs | 1 + .../TranslateTransformXAnimation.cs | 1 + .../TranslateTransformYAnimation.cs | 1 + PCL2.Neo/Animations/XAnimation.cs | 105 +++++++++++ PCL2.Neo/Animations/YAnimation.cs | 105 +++++++++++ PCL2.Neo/App.axaml | 1 + PCL2.Neo/Controls/MyButton.axaml | 4 +- PCL2.Neo/Controls/MyButton.axaml.cs | 20 ++- PCL2.Neo/Controls/MyIconButton.axaml.cs | 2 +- PCL2.Neo/Controls/MyLoading.axaml | 131 ++++++++++++++ PCL2.Neo/Controls/MyLoading.axaml.cs | 170 ++++++++++++++++++ PCL2.Neo/Controls/MyRadioButton.axaml.cs | 28 +-- PCL2.Neo/Helpers/AnimationHelper.cs | 52 +++++- PCL2.Neo/Helpers/NotificationHelper.cs | 18 ++ PCL2.Neo/PCL2.Neo.csproj | 4 + PCL2.Neo/Views/MainWindow.axaml | 42 ++++- PCL2.Neo/Views/MainWindow.axaml.cs | 28 ++- 25 files changed, 741 insertions(+), 45 deletions(-) create mode 100644 PCL2.Neo/Animations/Easings/EasePower.cs create mode 100644 PCL2.Neo/Animations/Easings/MyBackEaseIn.cs create mode 100644 PCL2.Neo/Animations/Easings/MyBackEaseOut.cs create mode 100644 PCL2.Neo/Animations/XAnimation.cs create mode 100644 PCL2.Neo/Animations/YAnimation.cs create mode 100644 PCL2.Neo/Controls/MyLoading.axaml create mode 100644 PCL2.Neo/Controls/MyLoading.axaml.cs create mode 100644 PCL2.Neo/Helpers/NotificationHelper.cs diff --git a/PCL2.Neo.sln.DotSettings.user b/PCL2.Neo.sln.DotSettings.user index 0fa3c1d..85c8e5f 100644 --- a/PCL2.Neo.sln.DotSettings.user +++ b/PCL2.Neo.sln.DotSettings.user @@ -1,5 +1,7 @@  + ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded @@ -7,6 +9,7 @@ ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded @@ -14,10 +17,15 @@ ForceIncluded ForceIncluded ForceIncluded + ForceIncluded + ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded + ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded diff --git a/PCL2.Neo/Animations/Easings/EasePower.cs b/PCL2.Neo/Animations/Easings/EasePower.cs new file mode 100644 index 0000000..3eae5fd --- /dev/null +++ b/PCL2.Neo/Animations/Easings/EasePower.cs @@ -0,0 +1,10 @@ +namespace PCL2.Neo.Animations.Easings +{ + public enum EasePower + { + Weak = 2, + Middle = 3, + Strong = 4, + ExtraStrong = 5 + } +} \ No newline at end of file diff --git a/PCL2.Neo/Animations/Easings/MyBackEaseIn.cs b/PCL2.Neo/Animations/Easings/MyBackEaseIn.cs new file mode 100644 index 0000000..350bc61 --- /dev/null +++ b/PCL2.Neo/Animations/Easings/MyBackEaseIn.cs @@ -0,0 +1,20 @@ +using Avalonia.Animation.Easings; +using System; + +namespace PCL2.Neo.Animations.Easings +{ + public class MyBackEaseIn : Easing + { + private readonly double p; + + public MyBackEaseIn(EasePower power = EasePower.Middle) + { + p = 3 - (int)power * 0.5; + } + + public override double Ease(double progress) + { + return Math.Pow(progress, p) * Math.Cos(1.5 * Math.PI * (1 - progress)); + } + } +} \ No newline at end of file diff --git a/PCL2.Neo/Animations/Easings/MyBackEaseOut.cs b/PCL2.Neo/Animations/Easings/MyBackEaseOut.cs new file mode 100644 index 0000000..31af238 --- /dev/null +++ b/PCL2.Neo/Animations/Easings/MyBackEaseOut.cs @@ -0,0 +1,20 @@ +using Avalonia.Animation.Easings; +using System; + +namespace PCL2.Neo.Animations.Easings +{ + public class MyBackEaseOut : Easing + { + private readonly double p; + + public MyBackEaseOut(EasePower power = EasePower.Middle) + { + p = 3 - (int)power * 0.5; + } + + public override double Ease(double progress) + { + return 1 - Math.Pow(1 - progress, p) * Math.Cos(1.5 * Math.PI * progress); + } + } +} \ No newline at end of file diff --git a/PCL2.Neo/Animations/IAnimation.cs b/PCL2.Neo/Animations/IAnimation.cs index a5e9e82..87569b3 100644 --- a/PCL2.Neo/Animations/IAnimation.cs +++ b/PCL2.Neo/Animations/IAnimation.cs @@ -7,22 +7,14 @@ namespace PCL2.Neo.Animations; public interface IAnimation { - /// - /// 要动画的控件。 - /// - Animatable Control { get; set; } - /// - /// 动画时间。 - /// - TimeSpan Duration { get; set; } /// /// 延迟。 /// TimeSpan Delay { get; set; } /// - /// 缓动效果。 + /// 指示动画是否要等待上一个动画完成后再执行。与 AnimationHelper 搭配使用。 /// - Easing Easing { get; set; } + bool Wait { get; set; } /// /// 异步形式执行动画。 /// diff --git a/PCL2.Neo/Animations/OpacityAnimation.cs b/PCL2.Neo/Animations/OpacityAnimation.cs index 3f020e5..e1692ce 100644 --- a/PCL2.Neo/Animations/OpacityAnimation.cs +++ b/PCL2.Neo/Animations/OpacityAnimation.cs @@ -17,6 +17,7 @@ public class OpacityAnimation : IAnimation public double? ValueBefore { get; set; } public double ValueAfter { get; set; } public Easing Easing { get; set; } + public bool Wait { get; set; } = false; public OpacityAnimation(Animatable control, double valueAfter) : this( control, valueAfter, new LinearEasing()) diff --git a/PCL2.Neo/Animations/RotateTransformAngleAnimation.cs b/PCL2.Neo/Animations/RotateTransformAngleAnimation.cs index aa147e5..2814b5d 100644 --- a/PCL2.Neo/Animations/RotateTransformAngleAnimation.cs +++ b/PCL2.Neo/Animations/RotateTransformAngleAnimation.cs @@ -17,6 +17,7 @@ public class RotateTransformAngleAnimation : IAnimation public double? ValueBefore { get; set; } public double ValueAfter { get; set; } public Easing Easing { get; set; } + public bool Wait { get; set; } = false; public RotateTransformAngleAnimation(Animatable control, double valueAfter) : this( control, valueAfter, new LinearEasing()) diff --git a/PCL2.Neo/Animations/ScaleTransformScaleXAnimation.cs b/PCL2.Neo/Animations/ScaleTransformScaleXAnimation.cs index a81bb09..ae9d8dc 100644 --- a/PCL2.Neo/Animations/ScaleTransformScaleXAnimation.cs +++ b/PCL2.Neo/Animations/ScaleTransformScaleXAnimation.cs @@ -17,6 +17,7 @@ public class ScaleTransformScaleXAnimation : IAnimation public double? ValueBefore { get; set; } public double ValueAfter { get; set; } public Easing Easing { get; set; } + public bool Wait { get; set; } = false; public ScaleTransformScaleXAnimation(Animatable control, double valueAfter) : this( control, valueAfter, new LinearEasing()) diff --git a/PCL2.Neo/Animations/ScaleTransformScaleYAnimation.cs b/PCL2.Neo/Animations/ScaleTransformScaleYAnimation.cs index 91347bd..171b625 100644 --- a/PCL2.Neo/Animations/ScaleTransformScaleYAnimation.cs +++ b/PCL2.Neo/Animations/ScaleTransformScaleYAnimation.cs @@ -17,6 +17,7 @@ public class ScaleTransformScaleYAnimation : IAnimation public double? ValueBefore { get; set; } public double ValueAfter { get; set; } public Easing Easing { get; set; } + public bool Wait { get; set; } = false; public ScaleTransformScaleYAnimation(Animatable control, double valueAfter) : this( control, valueAfter, new LinearEasing()) diff --git a/PCL2.Neo/Animations/TranslateTransformXAnimation.cs b/PCL2.Neo/Animations/TranslateTransformXAnimation.cs index 427854b..60bc682 100644 --- a/PCL2.Neo/Animations/TranslateTransformXAnimation.cs +++ b/PCL2.Neo/Animations/TranslateTransformXAnimation.cs @@ -17,6 +17,7 @@ public class TranslateTransformXAnimation : IAnimation public double? ValueBefore { get; set; } public double ValueAfter { get; set; } public Easing Easing { get; set; } + public bool Wait { get; set; } = false; public TranslateTransformXAnimation(Animatable control, double valueAfter) : this( control, valueAfter, new LinearEasing()) diff --git a/PCL2.Neo/Animations/TranslateTransformYAnimation.cs b/PCL2.Neo/Animations/TranslateTransformYAnimation.cs index 7e477f8..170c0f7 100644 --- a/PCL2.Neo/Animations/TranslateTransformYAnimation.cs +++ b/PCL2.Neo/Animations/TranslateTransformYAnimation.cs @@ -17,6 +17,7 @@ public class TranslateTransformYAnimation : IAnimation public double? ValueBefore { get; set; } public double ValueAfter { get; set; } public Easing Easing { get; set; } + public bool Wait { get; set; } = false; public TranslateTransformYAnimation(Animatable control, double valueAfter) : this( control, valueAfter, new LinearEasing()) diff --git a/PCL2.Neo/Animations/XAnimation.cs b/PCL2.Neo/Animations/XAnimation.cs new file mode 100644 index 0000000..a093867 --- /dev/null +++ b/PCL2.Neo/Animations/XAnimation.cs @@ -0,0 +1,105 @@ +using Avalonia; +using Avalonia.Animation; +using Avalonia.Animation.Easings; +using Avalonia.Layout; +using Avalonia.Media; +using Avalonia.Styling; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace PCL2.Neo.Animations +{ + public class XAnimation : IAnimation + { + private CancellationTokenSource _cancellationTokenSource; + public Animatable Control { get; set; } + public TimeSpan Duration { get; set; } + public TimeSpan Delay { get; set; } + public double Value { get; set; } + public Easing Easing { get; set; } + public bool Wait { get; set; } = false; + + public XAnimation(Animatable control, double value) : this( + control, value, new LinearEasing()) + { + } + public XAnimation(Animatable control, double value, Easing easing) : this( + control, TimeSpan.FromSeconds(1), value, easing) + { + } + public XAnimation(Animatable control, TimeSpan duration, double value) : this( + control, duration, value, new LinearEasing()) + { + } + public XAnimation(Animatable control, TimeSpan duration, TimeSpan delay, double value) : this( + control, duration, delay, value, new LinearEasing()) + { + } + public XAnimation(Animatable control, TimeSpan duration, double value, Easing easing) : this( + control, duration, TimeSpan.Zero, value, easing) + { + } + public XAnimation(Animatable control, TimeSpan duration, TimeSpan delay, double value, Easing easing) + { + Control = control; + Duration = duration; + Delay = delay; + Value = value; + Easing = easing; + _cancellationTokenSource = new CancellationTokenSource(); + } + + public async Task RunAsync() + { + var control = (Layoutable)Control; + Thickness marginOriginal = control.Margin; + Thickness margin; + switch (control.HorizontalAlignment) + { + case HorizontalAlignment.Left: + margin = new Thickness(control.Margin.Left + Value, control.Margin.Top, control.Margin.Right, + control.Margin.Bottom); + break; + case HorizontalAlignment.Right: + margin = new Thickness(control.Margin.Left, control.Margin.Top, control.Margin.Right - Value, + control.Margin.Bottom); + break; + default: + margin = control.Margin; + break; + } + var animation = new Animation + { + Easing = Easing, + Duration = Duration, + Delay = Delay, + FillMode = FillMode.Both, + Children = + { + new KeyFrame + { + Setters = + { + new Setter(Layoutable.MarginProperty, marginOriginal) + }, + Cue = new Cue(1d) + }, + new KeyFrame + { + Setters = + { + new Setter(Layoutable.MarginProperty, margin) + }, + Cue = new Cue(1d) + } + } + }; + await animation.RunAsync(Control, _cancellationTokenSource.Token); + } + public void Cancel() + { + _cancellationTokenSource.Cancel(); + } + } +} \ No newline at end of file diff --git a/PCL2.Neo/Animations/YAnimation.cs b/PCL2.Neo/Animations/YAnimation.cs new file mode 100644 index 0000000..6190ea7 --- /dev/null +++ b/PCL2.Neo/Animations/YAnimation.cs @@ -0,0 +1,105 @@ +using Avalonia; +using Avalonia.Animation; +using Avalonia.Animation.Easings; +using Avalonia.Layout; +using Avalonia.Media; +using Avalonia.Styling; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace PCL2.Neo.Animations +{ + public class YAnimation : IAnimation + { + private CancellationTokenSource _cancellationTokenSource; + public Animatable Control { get; set; } + public TimeSpan Duration { get; set; } + public TimeSpan Delay { get; set; } + public double Value { get; set; } + public Easing Easing { get; set; } + public bool Wait { get; set; } = false; + + public YAnimation(Animatable control, double value) : this( + control, value, new LinearEasing()) + { + } + public YAnimation(Animatable control, double value, Easing easing) : this( + control, TimeSpan.FromSeconds(1), value, easing) + { + } + public YAnimation(Animatable control, TimeSpan duration, double value) : this( + control, duration, value, new LinearEasing()) + { + } + public YAnimation(Animatable control, TimeSpan duration, TimeSpan delay, double value) : this( + control, duration, delay, value, new LinearEasing()) + { + } + public YAnimation(Animatable control, TimeSpan duration, double value, Easing easing) : this( + control, duration, TimeSpan.Zero, value, easing) + { + } + public YAnimation(Animatable control, TimeSpan duration, TimeSpan delay, double value, Easing easing) + { + Control = control; + Duration = duration; + Delay = delay; + Value = value; + Easing = easing; + _cancellationTokenSource = new CancellationTokenSource(); + } + + public async Task RunAsync() + { + var control = (Layoutable)Control; + Thickness marginOriginal = control.Margin; + Thickness margin; + switch (control.VerticalAlignment) + { + case VerticalAlignment.Top: + margin = new Thickness(control.Margin.Left, control.Margin.Top + Value, control.Margin.Right, + control.Margin.Bottom); + break; + case VerticalAlignment.Bottom: + margin = new Thickness(control.Margin.Left, control.Margin.Top, control.Margin.Right, + control.Margin.Bottom - Value); + break; + default: + margin = control.Margin; + break; + } + var animation = new Animation + { + Easing = Easing, + Duration = Duration, + Delay = Delay, + FillMode = FillMode.Both, + Children = + { + new KeyFrame + { + Setters = + { + new Setter(Layoutable.MarginProperty, marginOriginal) + }, + Cue = new Cue(1d) + }, + new KeyFrame + { + Setters = + { + new Setter(Layoutable.MarginProperty, margin) + }, + Cue = new Cue(1d) + } + } + }; + await animation.RunAsync(Control, _cancellationTokenSource.Token); + } + public void Cancel() + { + _cancellationTokenSource.Cancel(); + } + } +} \ No newline at end of file diff --git a/PCL2.Neo/App.axaml b/PCL2.Neo/App.axaml index 11bed62..0e9ab8e 100644 --- a/PCL2.Neo/App.axaml +++ b/PCL2.Neo/App.axaml @@ -28,6 +28,7 @@ + + + + + diff --git a/PCL2.Neo/Controls/MyLoading.axaml.cs b/PCL2.Neo/Controls/MyLoading.axaml.cs new file mode 100644 index 0000000..bbef6ec --- /dev/null +++ b/PCL2.Neo/Controls/MyLoading.axaml.cs @@ -0,0 +1,170 @@ +using Avalonia; +using Avalonia.Animation.Easings; +using Avalonia.Controls; +using Avalonia.Controls.Metadata; +using Avalonia.Controls.Primitives; +using Avalonia.Controls.Shapes; +using Avalonia.Media; +using Avalonia.Threading; +using PCL2.Neo.Animations; +using PCL2.Neo.Animations.Easings; +using PCL2.Neo.Helpers; +using System; +using System.Threading.Tasks; + +namespace PCL2.Neo.Controls +{ + [PseudoClasses(":unloaded", ":loading", ":stopped", ":error")] + public class MyLoading : TemplatedControl + { + private AnimationHelper _animation; + private Path? _pathPickaxe; + private Path? _pathError; + private Path? _pathLeft; + private Path? _pathRight; + private bool _hasErrorOccurred = false; + + public MyLoading() + { + _animation = new(); + } + + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) + { + base.OnApplyTemplate(e); + _pathPickaxe = e.NameScope.Find("PathPickaxe"); + _pathError = e.NameScope.Find("PathError"); + _pathLeft = e.NameScope.Find("PathLeft"); + _pathRight = e.NameScope.Find("PathRight"); + + SetPseudoClasses(); + + StartAnimation(); + } + + public enum LoadingState + { + Unloaded = -1, + Loading = 0, + Stopped = 1, + Error = 2 + } + + public static readonly StyledProperty StateProperty = AvaloniaProperty.Register( + nameof(State), LoadingState.Loading); + + public LoadingState State + { + get => GetValue(StateProperty); + set + { + SetValue(StateProperty, value); + SetPseudoClasses(); + } + } + + private void StartAnimation() + { + Dispatcher.UIThread.InvokeAsync(async () => + { + while (true) + { + var currentState = State; + switch (currentState) + { + case LoadingState.Loading: + if (_hasErrorOccurred) + { + await AnimationErrorToLoadingAsync(); + } + _hasErrorOccurred = false; + await AnimationLoadingAsync(); + break; + case LoadingState.Error: + if (!_hasErrorOccurred) + { + _hasErrorOccurred = true; + await AnimationLoadingToErrorAsync(); + break; + } + await Task.Delay(100); + break; + default: + await Task.Delay(100); + break; + } + } + }); + } + + private async Task AnimationErrorToLoadingAsync() + { + _animation.CancelAndClear(); + _animation.Animations.AddRange( + [ + new RotateTransformAngleAnimation(this._pathPickaxe!, TimeSpan.FromMilliseconds(350), 55d, -20d, new MyBackEaseIn(EasePower.Weak)), + new OpacityAnimation(this._pathError!, TimeSpan.FromMilliseconds(100), 0d), + new ScaleTransformScaleXAnimation(this._pathError!, TimeSpan.FromMilliseconds(100), 1d, 0.5d), + new ScaleTransformScaleYAnimation(this._pathError!, TimeSpan.FromMilliseconds(400), 1d, 0.5d) + ]); + await _animation.RunAsync(); + } + + private async Task AnimationLoadingToErrorAsync() + { + _animation.CancelAndClear(); + _animation.Animations.AddRange( + [ + new RotateTransformAngleAnimation(this._pathPickaxe!, TimeSpan.FromMilliseconds(900), 55d, new CubicEaseOut()), + new OpacityAnimation(this._pathError!, TimeSpan.FromMilliseconds(300), 1d), + new ScaleTransformScaleXAnimation(this._pathError!, TimeSpan.FromMilliseconds(400), 0.5d, 1d, new MyBackEaseOut()), + new ScaleTransformScaleYAnimation(this._pathError!, TimeSpan.FromMilliseconds(400), 0.5d, 1d, new MyBackEaseOut()) + ]); + await _animation.RunAsync(); + } + + private async Task AnimationLoadingAsync() + { + // 循环动画,听说这里折磨龙猫很久(doge) + _animation.CancelAndClear(); + _animation.Animations.AddRange( + [ + new RotateTransformAngleAnimation(this._pathPickaxe!, TimeSpan.FromMilliseconds(350), 55d, -20d, new MyBackEaseIn(EasePower.Weak)), + new RotateTransformAngleAnimation(this._pathPickaxe!, TimeSpan.FromMilliseconds(900), 30d, 55d, new ElasticEaseOut()), + new RotateTransformAngleAnimation(this._pathPickaxe!, TimeSpan.FromMilliseconds(180), -20d, 30d), + new OpacityAnimation(this._pathLeft!, TimeSpan.FromMilliseconds(100), TimeSpan.FromMilliseconds(50), 1d, 0d), + new XAnimation(this._pathLeft!, TimeSpan.FromMilliseconds(180), -5d, new CubicEaseOut()), + new YAnimation(this._pathLeft!, TimeSpan.FromMilliseconds(180), -6d, new CubicEaseOut()), + new OpacityAnimation(this._pathRight!, TimeSpan.FromMilliseconds(100), TimeSpan.FromMilliseconds(50), 1d, 0d), + new XAnimation(this._pathRight!, TimeSpan.FromMilliseconds(180), 5d, new CubicEaseOut()), + new YAnimation(this._pathRight!, TimeSpan.FromMilliseconds(180), -6d, new CubicEaseOut()), + ]); + await _animation.RunAsync(); + this._pathLeft!.Margin = new Thickness(7,41,0,0); + this._pathRight!.Margin = new Thickness(14,41,0,0); + } + + private void SetPseudoClasses() + { + PseudoClasses.Remove(":unloaded"); + PseudoClasses.Remove(":loading"); + PseudoClasses.Remove(":stopped"); + PseudoClasses.Remove(":error"); + switch (State) + { + case LoadingState.Unloaded: + PseudoClasses.Set(":unloaded", true); + break; + case LoadingState.Loading: + PseudoClasses.Set(":loading", true); + break; + case LoadingState.Stopped: + PseudoClasses.Set(":stopped", true); + break; + case LoadingState.Error: + PseudoClasses.Set(":error", true); + break; + } + } + } +} \ No newline at end of file diff --git a/PCL2.Neo/Controls/MyRadioButton.axaml.cs b/PCL2.Neo/Controls/MyRadioButton.axaml.cs index 580418d..79e14c0 100644 --- a/PCL2.Neo/Controls/MyRadioButton.axaml.cs +++ b/PCL2.Neo/Controls/MyRadioButton.axaml.cs @@ -18,7 +18,7 @@ public class MyRadioButton : RadioButton private Path? _shapeLogo; private TextBlock? _labText; private Border? _panBack; - + private bool _isMouseDown = false; protected override void OnApplyTemplate(TemplateAppliedEventArgs e) @@ -27,18 +27,18 @@ protected override void OnApplyTemplate(TemplateAppliedEventArgs e) _shapeLogo = e.NameScope.Find("ShapeLogo")!; _labText = e.NameScope.Find("LabText")!; _panBack = e.NameScope.Find("PanBack")!; - + this.Loaded += (_, _) => RefreshColor(); - + _shapeLogo.Data = Geometry.Parse(Logo); _shapeLogo.RenderTransform = new ScaleTransform { ScaleX = LogoScale, ScaleY = LogoScale }; _labText.Text = Text; - + SetPseudoClass(); } public int Uuid = CoreUtils.GetUuid(); - + public static readonly StyledProperty LogoProperty = AvaloniaProperty.Register( nameof(Logo)); @@ -71,7 +71,7 @@ public double LogoScale } } } - + public static readonly StyledProperty TextProperty = AvaloniaProperty.Register( nameof(Text), string.Empty); @@ -94,8 +94,8 @@ public enum ColorState White, HighLight } - - public static readonly StyledProperty ColorTypeProperty = + + public static readonly StyledProperty ColorTypeProperty = AvaloniaProperty.Register(nameof(ColorType)); public ColorState ColorType @@ -107,7 +107,7 @@ public ColorState ColorType SetPseudoClass(); } } - + [Obsolete] private void SetCheck() { @@ -122,9 +122,9 @@ private void SetCheck() } } } - + private void SetPseudoClass() - { + { switch (ColorType) { case ColorState.White: @@ -135,14 +135,14 @@ private void SetPseudoClass() break; } } - + private void RefreshColor() { if (_shapeLogo is null || _labText is null) return; switch (ColorType) { case ColorState.White: - if (IsChecked.Value) + if (IsChecked!.Value) { _panBack!.Background = (SolidColorBrush)new MyColor(255, 255, 255); _shapeLogo.Fill = (IBrush?)Application.Current!.Resources["ColorBrush3"]; @@ -156,7 +156,7 @@ private void RefreshColor() } break; case ColorState.HighLight: - if (IsChecked.Value) + if (IsChecked!.Value) { _panBack!.Background = (IBrush?)Application.Current!.Resources["ColorBrush3"]; _shapeLogo.Fill = (SolidColorBrush)new MyColor(255, 255, 255); diff --git a/PCL2.Neo/Helpers/AnimationHelper.cs b/PCL2.Neo/Helpers/AnimationHelper.cs index 73c949c..931e4ea 100644 --- a/PCL2.Neo/Helpers/AnimationHelper.cs +++ b/PCL2.Neo/Helpers/AnimationHelper.cs @@ -11,18 +11,66 @@ public class AnimationHelper(List animations) { public List Animations { get; set; } = animations; public List Tasks { get; } = new List(); + public bool Loop { get; set; } = false; public AnimationHelper() : this([]){} public async Task RunAsync() { Tasks.Clear(); + + if (Loop) + { + while (true) + { + Tasks.Clear(); + await RunAsyncCore(); + if (!Loop) return; + } + } + + await RunAsyncCore(); + } + + private async Task RunAsyncCore() + { + // 根据 Wait 进行动画分组 + var groupedAnimations = new List>(); + var currentGroup = new List(); foreach (IAnimation animation in Animations) { - Tasks.Add(animation.RunAsync()); + if (animation.Wait) + { + if (currentGroup.Count > 0) + { + groupedAnimations.Add(new List(currentGroup)); + currentGroup.Clear(); + continue; + } + currentGroup.Add(animation); + } + else + { + currentGroup.Add(animation); + } } - await Task.WhenAll(Tasks); + if (currentGroup.Count > 0) + { + groupedAnimations.Add(new List(currentGroup)); + } + + currentGroup.Clear(); + + foreach (List list in groupedAnimations) + { + foreach (IAnimation animation in list) + { + Tasks.Add(animation.RunAsync()); + } + + await Task.WhenAll(Tasks); + } } public void Cancel() diff --git a/PCL2.Neo/Helpers/NotificationHelper.cs b/PCL2.Neo/Helpers/NotificationHelper.cs new file mode 100644 index 0000000..0716538 --- /dev/null +++ b/PCL2.Neo/Helpers/NotificationHelper.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; + +namespace PCL2.Neo.Helpers +{ + public static class NotificationHelper + { + public static async Task ShowMessageAsync(string message) + { + return await ShowMessageAsync(message, "提示"); + } + + public static async Task ShowMessageAsync(string message, string title) + { + // 没做完 + return 0; + } + } +} \ No newline at end of file diff --git a/PCL2.Neo/PCL2.Neo.csproj b/PCL2.Neo/PCL2.Neo.csproj index 7dbd186..47f2281 100644 --- a/PCL2.Neo/PCL2.Neo.csproj +++ b/PCL2.Neo/PCL2.Neo.csproj @@ -43,4 +43,8 @@ + + + + diff --git a/PCL2.Neo/Views/MainWindow.axaml b/PCL2.Neo/Views/MainWindow.axaml index 9bd3787..814a34e 100644 --- a/PCL2.Neo/Views/MainWindow.axaml +++ b/PCL2.Neo/Views/MainWindow.axaml @@ -17,13 +17,19 @@ xmlns:pc="using:PCL2.Neo.Controls" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> - + + + + + + @@ -191,18 +197,40 @@ + Margin="10" + Text="普通按钮" /> + Margin="10" + Text="高亮按钮" /> + Margin="10" + Text="红色按钮" /> + + + + + + + + + + + - + diff --git a/PCL2.Neo/Views/MainWindow.axaml.cs b/PCL2.Neo/Views/MainWindow.axaml.cs index 7665ef9..1294aca 100644 --- a/PCL2.Neo/Views/MainWindow.axaml.cs +++ b/PCL2.Neo/Views/MainWindow.axaml.cs @@ -4,6 +4,8 @@ using Avalonia.Interactivity; using Avalonia.Media; using PCL2.Neo.Animations; +using PCL2.Neo.Animations.Easings; +using PCL2.Neo.Controls; using PCL2.Neo.Helpers; using System; using System.Threading.Tasks; @@ -41,9 +43,9 @@ private async void AnimationIn() { var animation = new AnimationHelper( [ - new OpacityAnimation(this, TimeSpan.FromMilliseconds(250), TimeSpan.FromMilliseconds(100), 0d, 1d), - new TranslateTransformYAnimation(this, TimeSpan.FromMilliseconds(600), TimeSpan.FromMilliseconds(100), 60d, 0d, new BackEaseOut()), - new RotateTransformAngleAnimation(this, TimeSpan.FromMilliseconds(500), TimeSpan.FromMilliseconds(100), -4d, 0d, new BackEaseOut()) + new OpacityAnimation(this, TimeSpan.FromMilliseconds(250), 0d, 1d), + new TranslateTransformYAnimation(this, TimeSpan.FromMilliseconds(600), 60d, 0d, new MyBackEaseOut(EasePower.Weak)), + new RotateTransformAngleAnimation(this, TimeSpan.FromMilliseconds(500), -4d, 0d, new MyBackEaseOut(EasePower.Weak)) ]); await animation.RunAsync(); } @@ -56,13 +58,23 @@ private async Task AnimationOut() { var animation = new AnimationHelper( [ - new OpacityAnimation(this.MainBorder, TimeSpan.FromMilliseconds(140), TimeSpan.FromMilliseconds(40), 0d, new QuadraticEaseOut()), - new ScaleTransformScaleXAnimation(this.MainBorder, TimeSpan.FromMilliseconds(180), 0.88d), - new ScaleTransformScaleYAnimation(this.MainBorder, TimeSpan.FromMilliseconds(180), 0.88d), - new TranslateTransformYAnimation(this.MainBorder, TimeSpan.FromMilliseconds(180), 20d, new QuadraticEaseOut()), - new RotateTransformAngleAnimation(this.MainBorder, TimeSpan.FromMilliseconds(180), 0.6d, new QuadraticEaseInOut()) + new OpacityAnimation(this, TimeSpan.FromMilliseconds(140), TimeSpan.FromMilliseconds(40), 0d, new QuadraticEaseOut()), + new ScaleTransformScaleXAnimation(this, TimeSpan.FromMilliseconds(180), 0.88d), + new ScaleTransformScaleYAnimation(this, TimeSpan.FromMilliseconds(180), 0.88d), + new TranslateTransformYAnimation(this, TimeSpan.FromMilliseconds(180), 20d, new QuadraticEaseOut()), + new RotateTransformAngleAnimation(this, TimeSpan.FromMilliseconds(180), 0.6d, new QuadraticEaseInOut()) ]); await animation.RunAsync(); } } + + private void Button_OnClick(object? sender, RoutedEventArgs e) + { + this.TestLoading.State = MyLoading.LoadingState.Loading; + } + + private void Button2_OnClick(object? sender, RoutedEventArgs e) + { + this.TestLoading.State = MyLoading.LoadingState.Error; + } } \ No newline at end of file