重构动效实现

This commit is contained in:
polarboy
2024-07-02 12:33:44 +08:00
parent 99d4199223
commit 4ab2cac2fd
4 changed files with 119 additions and 137 deletions
@@ -15,17 +15,12 @@ internal static class TransitionInterceptor<TTransition, TValue>
{
_disposables = new Dictionary<object, IDisposable>();
}
public static bool DoTransitionPrefix(TTransition __instance, IObservable<TValue> progress)
{
if (!_disposables.ContainsKey(__instance) && __instance is INotifyTransitionCompleted notifier) {
var disposable = progress.Subscribe(onNext: d => {}, onCompleted: () =>
{
HandleCompleted(notifier, true);
}, onError:exception =>
{
HandleCompleted(notifier, false);
});
var disposable = progress.Subscribe(onNext: d => { }, onCompleted: () => { HandleCompleted(notifier, true); },
onError: exception => { HandleCompleted(notifier, false); });
_disposables.Add(notifier, disposable);
}
@@ -37,6 +32,7 @@ internal static class TransitionInterceptor<TTransition, TValue>
if (succeed) {
notifier.NotifyTransitionCompleted();
}
_disposables[notifier].Dispose();
_disposables.Remove(notifier);
}
@@ -44,30 +40,29 @@ internal static class TransitionInterceptor<TTransition, TValue>
internal static class TransitionInterceptorsRegister
{
private static readonly MethodInfo? DoTransitionMethodInfo;
static TransitionInterceptorsRegister()
{
DoTransitionMethodInfo = typeof(TransitionInterceptor<,>)
.GetMethod("DoTransitionPrefix", BindingFlags.Static | BindingFlags.Public);
}
public static void Register(Harmony harmony)
{
RegisterTransformOperationsTransition(harmony);
RegisterDoubleTransition(harmony);
}
private static void RegisterTransformOperationsTransition(Harmony harmony)
{
var origin = typeof(TransformOperationsTransition).GetMethod("DoTransition", BindingFlags.Instance | BindingFlags.NonPublic);
var prefixInterceptor = DoTransitionMethodInfo?.MakeGenericMethod(typeof(TransformOperationsTransition), typeof(ITransform));
var origin =
typeof(TransformOperationsTransition).GetMethod("DoTransition",
BindingFlags.Instance | BindingFlags.NonPublic);
var prefixInterceptor = typeof(TransitionInterceptor<,>)
.MakeGenericType(typeof(TransformOperationsTransition), typeof(ITransform))
.GetMethod("DoTransitionPrefix", BindingFlags.Static | BindingFlags.Public);
harmony.Patch(origin, prefix: new HarmonyMethod(prefixInterceptor));
}
private static void RegisterDoubleTransition(Harmony harmony)
{
var origin = typeof(DoubleTransition).GetMethod("DoTransition", BindingFlags.Instance | BindingFlags.NonPublic);
var prefixInterceptor = DoTransitionMethodInfo?.MakeGenericMethod(typeof(DoubleTransition), typeof(double));
var prefixInterceptor = typeof(TransitionInterceptor<,>)
.MakeGenericType(typeof(DoubleTransition), typeof(double))
.GetMethod("DoTransitionPrefix", BindingFlags.Static | BindingFlags.Public);
harmony.Patch(origin, prefix: new HarmonyMethod(prefixInterceptor));
}
}
+18 -75
View File
@@ -1,32 +1,17 @@
using System.Diagnostics;
using AtomUI.Media;
using Avalonia;
using Avalonia.Animation;
using Avalonia.Animation.Easings;
using Avalonia.Controls;
using Avalonia.Layout;
using Avalonia.Media;
using Microsoft.CSharp.RuntimeBinder;
using ColorTransition = Avalonia.Animation.ColorTransition;
namespace AtomUI.MotionScene;
public enum TransitionKind
{
BoxShadows,
Brush,
Color,
CornerRadius,
Double,
Float,
Integer,
Point,
PixelPoint,
RelativePoint,
Size,
Thickness,
TransformOperations,
Vector,
}
public record class MotionConfig
@@ -58,27 +43,27 @@ public abstract class AbstractMotion : AvaloniaObject, IMotion
private List<ITransition> _transitions;
// 定义我们目前支持的动效属性
protected static readonly StyledProperty<double> MotionWidthProperty =
Layoutable.WidthProperty.AddOwner<AbstractMotion>();
protected static readonly StyledProperty<double> MotionHeightProperty =
Layoutable.HeightProperty.AddOwner<AbstractMotion>();
protected static readonly StyledProperty<PixelPoint> MotionWindowPositionProperty =
AvaloniaProperty.Register<AbstractMotion, PixelPoint>(nameof(MotionWindowPosition));
protected static readonly StyledProperty<double> MotionOpacityProperty =
Visual.OpacityProperty.AddOwner<AbstractMotion>();
protected static readonly StyledProperty<double> MotionWidthProperty =
Visual.OpacityProperty.AddOwner<AbstractMotion>();
protected static readonly StyledProperty<double> MotionHeightProperty =
Visual.OpacityProperty.AddOwner<AbstractMotion>();
protected static readonly StyledProperty<Point> MotionRenderOffsetProperty =
AvaloniaProperty.Register<AbstractMotion, Point>(nameof(MotionRenderOffset));
protected static readonly StyledProperty<Rect> MotionRenderBoundsProperty =
AvaloniaProperty.Register<AbstractMotion, Rect>(nameof(MotionRenderBounds));
protected static readonly StyledProperty<RelativePoint> MotionRenderTransformOriginProperty =
AvaloniaProperty.Register<AbstractMotion, RelativePoint>(nameof(MotionRenderTransformOrigin));
protected static readonly StyledProperty<ITransform> MotionRenderTransformProperty =
AvaloniaProperty.Register<AbstractMotion, ITransform>(nameof(MotionRenderTransform));
protected double MotionOpacity
{
get => GetValue(MotionOpacityProperty);
set => SetValue(MotionOpacityProperty, value);
}
protected double MotionWidth
{
get => GetValue(MotionWidthProperty);
@@ -91,28 +76,10 @@ public abstract class AbstractMotion : AvaloniaObject, IMotion
set => SetValue(MotionHeightProperty, value);
}
protected PixelPoint MotionWindowPosition
protected RelativePoint MotionRenderTransformOrigin
{
get => GetValue(MotionWindowPositionProperty);
set => SetValue(MotionWindowPositionProperty, value);
}
protected double MotionOpacity
{
get => GetValue(MotionOpacityProperty);
set => SetValue(MotionOpacityProperty, value);
}
protected Point MotionRenderOffset
{
get => GetValue(MotionRenderOffsetProperty);
set => SetValue(MotionRenderOffsetProperty, value);
}
protected Rect MotionRenderBounds
{
get => GetValue(MotionRenderBoundsProperty);
set => SetValue(MotionRenderBoundsProperty, value);
get => GetValue(MotionRenderTransformOriginProperty);
set => SetValue(MotionRenderTransformOriginProperty, value);
}
protected ITransform MotionRenderTransform
@@ -168,32 +135,8 @@ public abstract class AbstractMotion : AvaloniaObject, IMotion
protected virtual ITransition NotifyBuildTransition(MotionConfig config)
{
TransitionBase transition = default!;
if (config.TransitionKind == TransitionKind.Brush) {
transition = new SolidColorBrushTransition();
} else if (config.TransitionKind == TransitionKind.Color) {
transition = new ColorTransition();
} else if (config.TransitionKind == TransitionKind.Double) {
if (config.TransitionKind == TransitionKind.Double) {
transition = new DoubleTransition();
} else if (config.TransitionKind == TransitionKind.Float) {
transition = new FloatTransition();
} else if (config.TransitionKind == TransitionKind.Integer) {
transition = new IntegerTransition();
} else if (config.TransitionKind == TransitionKind.Point) {
transition = new PointTransition();
} else if (config.TransitionKind == TransitionKind.PixelPoint) {
transition = new PixelPointTransition();
} else if (config.TransitionKind == TransitionKind.Size) {
transition = new SizeTransition();
} else if (config.TransitionKind == TransitionKind.Thickness) {
transition = new ThicknessTransition();
} else if (config.TransitionKind == TransitionKind.Vector) {
transition = new VectorTransition();
} else if (config.TransitionKind == TransitionKind.BoxShadows) {
transition = new BoxShadowsTransition();
} else if (config.TransitionKind == TransitionKind.CornerRadius) {
transition = new CornerRadiusTransition();
} else if (config.TransitionKind == TransitionKind.RelativePoint) {
transition = new RelativePointTransition();
} else if (config.TransitionKind == TransitionKind.TransformOperations) {
transition = new TransformOperationsTransition();
}
+45 -6
View File
@@ -10,17 +10,57 @@ public class CollapseMotion : AbstractMotion
: base(actor)
{}
public MotionConfig? OpacityConfig => GetMotionConfig(MotionOpacityProperty);
public MotionConfig? HeightConfig => GetMotionConfig(MotionHeightProperty);
public void ConfigureHeight(TimeSpan duration, Easing? easing = null)
{
easing ??= new CubicEaseInOut();
var motionEntity = GetMotionEntity();
var config = new MotionConfig(MotionHeightProperty)
{
TransitionKind = TransitionKind.Double,
StartValue = motionEntity.Bounds.Height,
EndValue = 0,
MotionDuration = duration,
MotionEasing = easing
};
AddMotionConfig(config);
}
public void ConfigureOpacity(TimeSpan duration, Easing? easing = null)
{
easing ??= new CubicEaseInOut();
var config = new MotionConfig(MotionOpacityProperty)
{
TransitionKind = TransitionKind.Double,
StartValue = 1d,
EndValue = 0d,
MotionDuration = duration,
MotionEasing = easing
};
AddMotionConfig(config);
}
}
public class ExpandMotion : AbstractMotion
{
public ExpandMotion(MotionActor actor)
: base(actor)
{}
public MotionConfig? OpacityConfig => GetMotionConfig(MotionOpacityProperty);
public MotionConfig? HeightConfig => GetMotionConfig(MotionHeightProperty);
public MotionConfig? WidthConfig => GetMotionConfig(MotionWidthProperty);
public void ConfigureHeight(double originHeight, TimeSpan duration, Easing? easing = null)
{
easing ??= new CubicEaseInOut();
var motionEntity = GetMotionEntity();
var config = new MotionConfig(MotionHeightProperty)
{
TransitionKind = TransitionKind.Double,
StartValue = originHeight,
EndValue = 0,
StartValue = 0,
EndValue = motionEntity.Bounds.Height,
MotionDuration = duration,
MotionEasing = easing
};
@@ -30,12 +70,11 @@ public class CollapseMotion : AbstractMotion
public void ConfigureOpacity(double originOpacity, TimeSpan duration, Easing? easing = null)
{
easing ??= new CubicEaseInOut();
originOpacity = Math.Clamp(originOpacity, 0, 1);
var config = new MotionConfig(MotionOpacityProperty)
{
TransitionKind = TransitionKind.Double,
StartValue = originOpacity,
EndValue = 0,
StartValue = 0d,
EndValue = 1d,
MotionDuration = duration,
MotionEasing = easing
};
+42 -37
View File
@@ -1,12 +1,13 @@
using Avalonia;
using Avalonia.Animation.Easings;
using Avalonia.Media;
namespace AtomUI.MotionScene;
public class MoveDownInMotion : AbstractMotion
{
public MotionConfig? OpacityConfig => GetMotionConfig(MotionOpacityProperty);
public MotionConfig? OffsetConfig => GetMotionConfig(MotionRenderOffsetProperty);
public MotionConfig? RenderTransformConfig => GetMotionConfig(MotionRenderTransformProperty);
public MoveDownInMotion(MotionActor actor)
: base(actor)
@@ -26,18 +27,19 @@ public class MoveDownInMotion : AbstractMotion
AddMotionConfig(config);
}
public void ConfigureOffset(TimeSpan duration, Easing? easing = null)
public void ConfigureTransform(TimeSpan duration, Easing? easing = null)
{
easing ??= new CircularEaseOut();
var target = GetMotionActor()?.Entity!;
var config = new MotionConfig(MotionRenderOffsetProperty)
var motionEntity = GetMotionActor().Entity;
var config = new MotionConfig(MotionRenderTransformProperty)
{
TransitionKind = TransitionKind.Point,
StartValue = new Point(target.Bounds.X, target.Bounds.Bottom),
EndValue = new Point(target.Bounds.X, 0),
TransitionKind = TransitionKind.TransformOperations,
StartValue = new TranslateTransform(0, motionEntity.Bounds.Bottom),
EndValue = new TranslateTransform(0, 0),
MotionDuration = duration,
MotionEasing = easing
};
AddMotionConfig(config);
}
}
@@ -45,7 +47,7 @@ public class MoveDownInMotion : AbstractMotion
public class MoveDownOutMotion : AbstractMotion
{
public MotionConfig? OpacityConfig => GetMotionConfig(MotionOpacityProperty);
public MotionConfig? OffsetConfig => GetMotionConfig(MotionRenderOffsetProperty);
public MotionConfig? RenderTransformConfig => GetMotionConfig(MotionRenderTransformProperty);
public MoveDownOutMotion(MotionActor actor)
: base(actor)
@@ -65,15 +67,16 @@ public class MoveDownOutMotion : AbstractMotion
AddMotionConfig(config);
}
public void ConfigureOffset(TimeSpan duration, Easing? easing = null)
public void ConfigureTransform(TimeSpan duration, Easing? easing = null)
{
easing ??= new CircularEaseInOut();
var motionEntity = GetMotionEntity();
var config = new MotionConfig(MotionRenderOffsetProperty)
var config = new MotionConfig(MotionRenderTransformProperty)
{
TransitionKind = TransitionKind.Point,
StartValue = new Point(motionEntity.Bounds.X, 0),
EndValue = new Point(motionEntity.Bounds.X, motionEntity.Bounds.Bottom),
TransitionKind = TransitionKind.TransformOperations,
StartValue = new TranslateTransform(0, 0),
EndValue = new TranslateTransform(0, motionEntity.Bounds.Bottom),
MotionDuration = duration,
MotionEasing = easing
};
@@ -84,7 +87,7 @@ public class MoveDownOutMotion : AbstractMotion
public class MoveLeftInMotion : AbstractMotion
{
public MotionConfig? OpacityConfig => GetMotionConfig(MotionOpacityProperty);
public MotionConfig? OffsetConfig => GetMotionConfig(MotionRenderOffsetProperty);
public MotionConfig? RenderTransformConfig => GetMotionConfig(MotionRenderTransformProperty);
public MoveLeftInMotion(MotionActor actor)
: base(actor)
@@ -104,15 +107,15 @@ public class MoveLeftInMotion : AbstractMotion
AddMotionConfig(config);
}
public void ConfigureOffset(TimeSpan duration, Easing? easing = null)
public void ConfigureTransform(TimeSpan duration, Easing? easing = null)
{
easing ??= new CircularEaseOut();
var motionEntity = GetMotionEntity();
var config = new MotionConfig(MotionRenderOffsetProperty)
var config = new MotionConfig(MotionRenderTransformProperty)
{
TransitionKind = TransitionKind.Point,
StartValue = new Point(motionEntity.Bounds.X - motionEntity.Bounds.Width, motionEntity.Bounds.Y),
EndValue = new Point(motionEntity.Bounds.X, motionEntity.Bounds.Y),
TransitionKind = TransitionKind.TransformOperations,
StartValue = new TranslateTransform(- motionEntity.Bounds.Width, 0),
EndValue = new TranslateTransform(0, 0),
MotionDuration = duration,
MotionEasing = easing
};
@@ -123,7 +126,7 @@ public class MoveLeftInMotion : AbstractMotion
public class MoveLeftOutMotion : AbstractMotion
{
public MotionConfig? OpacityConfig => GetMotionConfig(MotionOpacityProperty);
public MotionConfig? OffsetConfig => GetMotionConfig(MotionRenderOffsetProperty);
public MotionConfig? RenderTransformConfig => GetMotionConfig(MotionRenderTransformProperty);
public MoveLeftOutMotion(MotionActor actor)
: base(actor)
@@ -143,18 +146,20 @@ public class MoveLeftOutMotion : AbstractMotion
AddMotionConfig(config);
}
public void ConfigureOffset(TimeSpan duration, Easing? easing = null)
public void ConfigureTransform(TimeSpan duration, Easing? easing = null)
{
easing ??= new CircularEaseInOut();
var motionEntity = GetMotionEntity();
var config = new MotionConfig(MotionRenderOffsetProperty)
var config = new MotionConfig(MotionRenderTransformProperty)
{
TransitionKind = TransitionKind.Point,
StartValue = new Point(motionEntity.Bounds.X, motionEntity.Bounds.Y),
EndValue = new Point(motionEntity.Bounds.X - motionEntity.Bounds.Width, motionEntity.Bounds.Y),
TransitionKind = TransitionKind.TransformOperations,
StartValue = new TranslateTransform(0, 0),
EndValue = new TranslateTransform( - motionEntity.Bounds.Width, 0),
MotionDuration = duration,
MotionEasing = easing
};
AddMotionConfig(config);
}
}
@@ -162,7 +167,7 @@ public class MoveLeftOutMotion : AbstractMotion
public class MoveRightInMotion : AbstractMotion
{
public MotionConfig? OpacityConfig => GetMotionConfig(MotionOpacityProperty);
public MotionConfig? OffsetConfig => GetMotionConfig(MotionRenderOffsetProperty);
public MotionConfig? RenderTransformConfig => GetMotionConfig(MotionRenderTransformProperty);
public MoveRightInMotion(MotionActor actor)
: base(actor)
@@ -182,15 +187,15 @@ public class MoveRightInMotion : AbstractMotion
AddMotionConfig(config);
}
public void ConfigureOffset(TimeSpan duration, Easing? easing = null)
public void ConfigureTransform(TimeSpan duration, Easing? easing = null)
{
easing ??= new CircularEaseOut();
var motionEntity = GetMotionEntity();
var config = new MotionConfig(MotionRenderOffsetProperty)
var config = new MotionConfig(MotionRenderTransformProperty)
{
TransitionKind = TransitionKind.Point,
StartValue = new Point(motionEntity.Bounds.Right, motionEntity.Bounds.Y),
EndValue = new Point(motionEntity.Bounds.X, motionEntity.Bounds.Y),
TransitionKind = TransitionKind.TransformOperations,
StartValue = new TranslateTransform(motionEntity.Bounds.Right, 0),
EndValue = new TranslateTransform(0, 0),
MotionDuration = duration,
MotionEasing = easing
};
@@ -201,7 +206,7 @@ public class MoveRightInMotion : AbstractMotion
public class MoveRightOutMotion : AbstractMotion
{
public MotionConfig? OpacityConfig => GetMotionConfig(MotionOpacityProperty);
public MotionConfig? OffsetConfig => GetMotionConfig(MotionRenderOffsetProperty);
public MotionConfig? RenderTransformConfig => GetMotionConfig(MotionRenderTransformProperty);
public MoveRightOutMotion(MotionActor actor)
: base(actor)
@@ -221,15 +226,15 @@ public class MoveRightOutMotion : AbstractMotion
AddMotionConfig(config);
}
public void ConfigureOffset(TimeSpan duration, Easing? easing = null)
public void ConfigureTransform(TimeSpan duration, Easing? easing = null)
{
easing ??= new CircularEaseInOut();
var motionEntity = GetMotionEntity();
var config = new MotionConfig(MotionRenderOffsetProperty)
var config = new MotionConfig(MotionRenderTransformProperty)
{
TransitionKind = TransitionKind.Point,
StartValue = new Point(motionEntity.Bounds.X, motionEntity.Bounds.Y),
EndValue = new Point(motionEntity.Bounds.Right, motionEntity.Bounds.Y),
TransitionKind = TransitionKind.TransformOperations,
StartValue = new TranslateTransform(0, 0),
EndValue = new TranslateTransform(motionEntity.Bounds.Right, 0),
MotionDuration = duration,
MotionEasing = easing
};