Implementing a new animation execution mechanism

This commit is contained in:
polarboy 2024-09-29 14:25:21 +08:00
parent 03422c53a6
commit 28abd64b04
7 changed files with 76 additions and 70 deletions

View File

@ -2,6 +2,7 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.Media.Transformation;
namespace AtomUI.Controls.Primitives;
@ -9,10 +10,10 @@ public class MotionActorControl : Decorator
{
#region
public static readonly StyledProperty<ITransform?> MotionTransformProperty =
AvaloniaProperty.Register<MotionActorControl, ITransform?>(nameof(MotionTransform));
public static readonly StyledProperty<TransformOperations?> MotionTransformProperty =
AvaloniaProperty.Register<MotionActorControl, TransformOperations?>(nameof(MotionTransform));
public ITransform? MotionTransform
public TransformOperations? MotionTransform
{
get => GetValue(MotionTransformProperty);
set => SetValue(MotionTransformProperty, value);
@ -58,6 +59,7 @@ public class MotionActorControl : Decorator
ChildProperty.Changed
.AddClassHandler<MotionActorControl>((x, _) => x.HandleChildChanged());
AffectsRender<MotionActorControl>(MotionTransformProperty);
}
private void HandleLayoutTransformChanged(AvaloniaPropertyChangedEventArgs e)
@ -108,7 +110,7 @@ public class MotionActorControl : Decorator
}
_transformation = matrix;
_matrixTransform.Matrix = matrix;
_matrixTransform.Matrix = FilterScaleTransform(matrix);
// New transform means re-layout is necessary
InvalidateMeasure();
}
@ -130,6 +132,17 @@ public class MotionActorControl : Decorator
matrix.M32);
}
private static Matrix FilterScaleTransform(Matrix matrix)
{
return new Matrix(
1.0,
matrix.M12,
matrix.M21,
1.0,
matrix.M31,
matrix.M32);
}
protected override Size ArrangeOverride(Size finalSize)
{
if (MotionTransformRoot == null || MotionTransform == null)
@ -184,7 +197,6 @@ public class MotionActorControl : Decorator
protected override Size MeasureOverride(Size availableSize)
{
Console.WriteLine(MotionTransform);
if (MotionTransformRoot == null || MotionTransform == null)
{
return base.MeasureOverride(availableSize);

View File

@ -6,7 +6,7 @@ using Avalonia.Styling;
namespace AtomUI.Controls.Utils;
public static partial class MotionFactory
internal static partial class MotionFactory
{
public static MotionConfig BuildCollapseMotion(Direction direction, TimeSpan duration, Easing? easing = null,
FillMode fillMode = FillMode.None)

View File

@ -1,9 +1,10 @@
using Avalonia;
using Avalonia.Animation;
using Avalonia.Media.Transformation;
namespace AtomUI.Controls.Utils;
public record MotionConfig
internal record MotionConfig
{
public RelativePoint RenderTransformOrigin { get; }
public IList<Animation> Animations { get; }
@ -13,4 +14,36 @@ public record MotionConfig
RenderTransformOrigin = renderTransformOrigin;
Animations = animations;
}
}
internal static partial class MotionFactory
{
static TransformOperations BuildScaleTransform(double scaleX, double scaleY)
{
var builder = new TransformOperations.Builder(1);
builder.AppendScale(scaleX, scaleY);
return builder.Build();
}
static TransformOperations BuildScaleTransform(double scale)
{
return BuildScaleTransform(scale, scale);
}
static TransformOperations BuildScaleXTransform(double scale)
{
return BuildScaleTransform(scale, 1.0);
}
static TransformOperations BuildScaleYTransform(double scale)
{
return BuildScaleTransform(1.0, scale);
}
static TransformOperations BuildTranslateTransform(double offsetX, double offsetY)
{
var builder = new TransformOperations.Builder(1);
builder.AppendTranslate(offsetX, offsetY);
return builder.Build();
}
}

View File

@ -1,24 +1,26 @@
using Avalonia;
using AtomUI.Controls.Primitives;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Threading;
namespace AtomUI.Controls.Utils;
public static class MotionInvoker
internal static class MotionInvoker
{
public static void Invoke(Control target,
MotionConfig motionConfig,
public static void Invoke(MotionActorControl target,
MotionConfig motionConfig,
Action? aboutToStart = null,
Action? completedAction = null)
{
Dispatcher.UIThread.InvokeAsync(async () =>
{
using var originRestore = new RenderTransformOriginRestore(target);
using var originRestore = new RenderTransformOriginRestore(target);
target.RenderTransformOrigin = motionConfig.RenderTransformOrigin;
if (aboutToStart != null)
{
aboutToStart();
}
foreach (var animation in motionConfig.Animations)
{
await animation.RunAsync(target);
@ -42,7 +44,7 @@ internal class RenderTransformOriginRestore : IDisposable
_target = target;
_origin = target.RenderTransformOrigin;
}
public void Dispose()
{
_target.RenderTransformOrigin = _origin;

View File

@ -4,7 +4,7 @@ using Avalonia.Media.Transformation;
namespace AtomUI.Controls.Utils;
public class MotionTransformOptionsAnimator : InterpolatingAnimator<TransformOperations>
internal class MotionTransformOptionsAnimator : InterpolatingAnimator<TransformOperations>
{
public override TransformOperations Interpolate(double progress, TransformOperations oldValue, TransformOperations newValue)
{

View File

@ -6,7 +6,7 @@ using Avalonia.Styling;
namespace AtomUI.Controls.Utils;
public static partial class MotionFactory
internal static partial class MotionFactory
{
public static MotionConfig BuildMoveDownInMotion(double offset, TimeSpan duration, Easing? easing = null,
FillMode fillMode = FillMode.None)

View File

@ -1,17 +1,19 @@
using Avalonia;
using AtomUI.Controls.Primitives;
using Avalonia;
using Avalonia.Animation;
using Avalonia.Animation.Easings;
using Avalonia.Media;
using Avalonia.Media.Transformation;
using Avalonia.Styling;
namespace AtomUI.Controls.Utils;
public static partial class MotionFactory
internal static partial class MotionFactory
{
public static MotionConfig BuildSlideUpInMotion(TimeSpan duration, Easing? easing = null,
FillMode fillMode = FillMode.None)
{
easing ??= new QuinticEaseOut();
easing ??= new CubicEaseOut();
var animations = new List<Animation>();
RelativePoint transformOrigin = default;
var animation = new Animation
@ -32,36 +34,14 @@ public static partial class MotionFactory
Value = 0.0
};
startFrame.Setters.Add(opacitySetter);
var scaleYSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 0.1
Property = MotionActorControl.MotionTransformProperty,
Value = BuildScaleYTransform(0.01) // // 不知道为啥设置成 0.0, 子元素渲染不正常
};
startFrame.Setters.Add(scaleYSetter);
}
animation.Children.Add(startFrame);
var middleFrame = new KeyFrame
{
Cue = new Cue(0.9)
};
{
var opacitySetter = new Setter
{
Property = Visual.OpacityProperty,
Value = 0.2
};
middleFrame.Setters.Add(opacitySetter);
var scaleYSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 0.9
};
middleFrame.Setters.Add(scaleYSetter);
}
animation.Children.Add(middleFrame);
var endFrame = new KeyFrame
{
@ -76,8 +56,8 @@ public static partial class MotionFactory
endFrame.Setters.Add(opacitySetter);
var scaleYSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 1.0
Property = MotionActorControl.MotionTransformProperty,
Value = BuildScaleYTransform(1.0)
};
endFrame.Setters.Add(scaleYSetter);
}
@ -91,7 +71,7 @@ public static partial class MotionFactory
public static MotionConfig BuildSlideUpOutMotion(TimeSpan duration, Easing? easing = null,
FillMode fillMode = FillMode.None)
{
easing ??= new QuinticEaseIn();
easing ??= new CubicEaseIn();
var animations = new List<Animation>();
RelativePoint transformOrigin = default;
var animation = new Animation
@ -115,33 +95,12 @@ public static partial class MotionFactory
var scaleYSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 1.0
Property = MotionActorControl.MotionTransformProperty,
Value = BuildScaleYTransform(1.0)
};
startFrame.Setters.Add(scaleYSetter);
}
animation.Children.Add(startFrame);
var middleFrame = new KeyFrame
{
Cue = new Cue(0.9)
};
{
var opacitySetter = new Setter
{
Property = Visual.OpacityProperty,
Value = 0.2
};
middleFrame.Setters.Add(opacitySetter);
var scaleYSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 0.9
};
middleFrame.Setters.Add(scaleYSetter);
}
animation.Children.Add(middleFrame);
var endFrame = new KeyFrame
{
@ -156,8 +115,8 @@ public static partial class MotionFactory
endFrame.Setters.Add(opacitySetter);
var scaleYSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 0.0
Property = MotionActorControl.MotionTransformProperty,
Value = BuildScaleYTransform(0.0)
};
endFrame.Setters.Add(scaleYSetter);
}