mirror of
https://gitee.com/chinware/atomui.git
synced 2024-11-29 18:38:16 +08:00
Add AbstractMotion
This commit is contained in:
parent
2ef0690a96
commit
e7bc16ad4e
@ -1,188 +1,72 @@
|
||||
using System.Diagnostics;
|
||||
using System.Reactive.Linq;
|
||||
using AtomUI.Media;
|
||||
using Avalonia;
|
||||
using Avalonia;
|
||||
using Avalonia.Animation;
|
||||
using Avalonia.Animation.Easings;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Media.Transformation;
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace AtomUI.MotionScene;
|
||||
|
||||
public enum TransitionKind
|
||||
internal class AbstractMotion : IMotion
|
||||
{
|
||||
Double,
|
||||
TransformOperations
|
||||
}
|
||||
public bool IsRunning { get; }
|
||||
|
||||
public record class MotionConfig
|
||||
{
|
||||
public AvaloniaProperty Property { get; set; }
|
||||
public object? StartValue { get; set; }
|
||||
public object? EndValue { get; set; }
|
||||
public Easing MotionEasing { get; set; } = new LinearEasing();
|
||||
public TimeSpan MotionDuration { get; set; } = TimeSpan.FromMilliseconds(300);
|
||||
public TransitionKind TransitionKind { get; set; }
|
||||
public RelativePoint RenderTransformOrigin { get; protected set; }
|
||||
public IList<Animation> Animations { get; }
|
||||
public TimeSpan Duration { get; }
|
||||
public Easing Easing { get; }
|
||||
public FillMode PropertyValueFillMode { get; }
|
||||
|
||||
public MotionConfig(AvaloniaProperty targetProperty, object? startValue = null, object? endValue = null)
|
||||
public AbstractMotion(TimeSpan duration, Easing? easing = null, FillMode fillMode = FillMode.None)
|
||||
{
|
||||
Property = targetProperty;
|
||||
StartValue = startValue;
|
||||
EndValue = endValue;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class AbstractMotion : AvaloniaObject, IMotion
|
||||
{
|
||||
public bool IsRunning { get; } = false;
|
||||
|
||||
private readonly Dictionary<AvaloniaProperty, MotionConfig> _motionConfigs;
|
||||
private readonly List<ITransition> _transitions;
|
||||
public IObservable<bool>? CompletedObservable { get; private set; }
|
||||
|
||||
// 定义我们目前支持的动效属性
|
||||
public static readonly StyledProperty<double> MotionOpacityProperty =
|
||||
Visual.OpacityProperty.AddOwner<AbstractMotion>();
|
||||
|
||||
public static readonly StyledProperty<double> MotionWidthProperty =
|
||||
Layoutable.WidthProperty.AddOwner<AbstractMotion>();
|
||||
|
||||
public static readonly StyledProperty<double> MotionHeightProperty =
|
||||
Layoutable.HeightProperty.AddOwner<AbstractMotion>();
|
||||
|
||||
public static readonly StyledProperty<RelativePoint> MotionRenderTransformOriginProperty =
|
||||
Visual.RenderTransformOriginProperty.AddOwner<AbstractMotion>();
|
||||
|
||||
public static readonly StyledProperty<ITransform?> MotionRenderTransformProperty =
|
||||
Visual.RenderTransformProperty.AddOwner<AbstractMotion>();
|
||||
|
||||
protected double MotionOpacity
|
||||
{
|
||||
get => GetValue(MotionOpacityProperty);
|
||||
set => SetValue(MotionOpacityProperty, value);
|
||||
Animations = new List<Animation>();
|
||||
Duration = duration;
|
||||
Easing = easing ?? new LinearEasing();
|
||||
PropertyValueFillMode = fillMode;
|
||||
}
|
||||
|
||||
protected double MotionWidth
|
||||
public async Task RunAsync(MotionActorControl actor,
|
||||
Action? aboutToStart = null,
|
||||
Action? completedAction = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
get => GetValue(MotionWidthProperty);
|
||||
set => SetValue(MotionWidthProperty, value);
|
||||
}
|
||||
|
||||
protected double MotionHeight
|
||||
{
|
||||
get => GetValue(MotionHeightProperty);
|
||||
set => SetValue(MotionHeightProperty, value);
|
||||
}
|
||||
|
||||
internal RelativePoint MotionRenderTransformOrigin
|
||||
{
|
||||
get => GetValue(MotionRenderTransformOriginProperty);
|
||||
set => SetValue(MotionRenderTransformOriginProperty, value);
|
||||
}
|
||||
|
||||
protected ITransform? MotionRenderTransform
|
||||
{
|
||||
get => GetValue(MotionRenderTransformProperty);
|
||||
set => SetValue(MotionRenderTransformProperty, value);
|
||||
}
|
||||
|
||||
public AbstractMotion()
|
||||
{
|
||||
_motionConfigs = new Dictionary<AvaloniaProperty, MotionConfig>();
|
||||
_transitions = new List<ITransition>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建动效动画对象
|
||||
/// </summary>
|
||||
/// <param name="motionTarget"></param>
|
||||
/// <returns></returns>
|
||||
internal List<ITransition> BuildTransitions(Control motionTarget)
|
||||
{
|
||||
foreach (var entry in _motionConfigs)
|
||||
Configure();
|
||||
await Dispatcher.UIThread.InvokeAsync(async () =>
|
||||
{
|
||||
var config = entry.Value;
|
||||
NotifyPreBuildTransition(config, motionTarget);
|
||||
var transition = NotifyBuildTransition(config);
|
||||
_transitions.Add(transition);
|
||||
}
|
||||
|
||||
var completedObservables = new IObservable<bool>[_transitions.Count];
|
||||
for (var i = 0; i < _transitions.Count; ++i)
|
||||
{
|
||||
var transition = _transitions[i];
|
||||
if (transition is INotifyTransitionCompleted notifyTransitionCompleted)
|
||||
using var originRestore = new RenderTransformOriginRestore(actor);
|
||||
actor.RenderTransformOrigin = RenderTransformOrigin;
|
||||
if (aboutToStart is not null)
|
||||
{
|
||||
completedObservables[i] = notifyTransitionCompleted.CompletedObservable;
|
||||
aboutToStart();
|
||||
}
|
||||
}
|
||||
|
||||
CompletedObservable =
|
||||
Observable.CombineLatest(completedObservables).Select(list => { return list.All(v => v); });
|
||||
return _transitions;
|
||||
NotifyPreStart();
|
||||
|
||||
foreach (var animation in Animations)
|
||||
{
|
||||
await animation.RunAsync(actor, cancellationToken);
|
||||
}
|
||||
|
||||
if (completedAction is not null)
|
||||
{
|
||||
completedAction();
|
||||
}
|
||||
|
||||
NotifyCompleted();
|
||||
});
|
||||
}
|
||||
|
||||
// 生命周期接口
|
||||
internal virtual void NotifyPreStart()
|
||||
protected virtual void Configure()
|
||||
{
|
||||
}
|
||||
|
||||
internal virtual void NotifyStarted()
|
||||
protected virtual void NotifyPreStart()
|
||||
{
|
||||
}
|
||||
|
||||
internal virtual void NotifyCompleted()
|
||||
protected virtual void NotifyCompleted()
|
||||
{
|
||||
}
|
||||
|
||||
internal virtual void NotifyConfigMotionTarget(Control motionTarget)
|
||||
{
|
||||
}
|
||||
|
||||
internal virtual void NotifyRestoreMotionTarget(Control motionTarget)
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void NotifyPreBuildTransition(MotionConfig config, Control motionTarget)
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual ITransition NotifyBuildTransition(MotionConfig config)
|
||||
{
|
||||
TransitionBase transition = default!;
|
||||
if (config.TransitionKind == TransitionKind.Double)
|
||||
{
|
||||
transition = new NotifiableDoubleTransition();
|
||||
}
|
||||
else if (config.TransitionKind == TransitionKind.TransformOperations)
|
||||
{
|
||||
transition = new NotifiableTransformOperationsTransition();
|
||||
}
|
||||
|
||||
transition.Property = config.Property;
|
||||
transition.Duration = config.MotionDuration;
|
||||
transition.Easing = config.MotionEasing;
|
||||
return transition;
|
||||
}
|
||||
|
||||
protected MotionConfig? GetMotionConfig(AvaloniaProperty property)
|
||||
{
|
||||
if (_motionConfigs.TryGetValue(property, out var motionConfig))
|
||||
{
|
||||
return motionConfig;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void AddMotionConfig(MotionConfig config)
|
||||
{
|
||||
Debug.Assert(!_motionConfigs.ContainsKey(config.Property));
|
||||
_motionConfigs.Add(config.Property, config);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算顶层动画渲染层的大小
|
||||
/// </summary>
|
||||
@ -208,42 +92,52 @@ public abstract class AbstractMotion : AvaloniaObject, IMotion
|
||||
return motionTargetPosition;
|
||||
}
|
||||
|
||||
public IList<AvaloniaProperty> GetActivatedProperties()
|
||||
{
|
||||
return _motionConfigs.Keys.ToList();
|
||||
}
|
||||
|
||||
public IList<MotionConfig> GetMotionConfigs()
|
||||
{
|
||||
return _motionConfigs.Values.ToList();
|
||||
}
|
||||
|
||||
protected TransformOperations BuildScaleTransform(double scaleX, double scaleY)
|
||||
protected static TransformOperations BuildScaleTransform(double scaleX, double scaleY)
|
||||
{
|
||||
var builder = new TransformOperations.Builder(1);
|
||||
builder.AppendScale(scaleX, scaleY);
|
||||
return builder.Build();
|
||||
}
|
||||
|
||||
protected TransformOperations BuildScaleTransform(double scale)
|
||||
protected static TransformOperations BuildScaleTransform(double scale)
|
||||
{
|
||||
return BuildScaleTransform(scale, scale);
|
||||
}
|
||||
|
||||
protected TransformOperations BuildScaleXTransform(double scale)
|
||||
protected static TransformOperations BuildScaleXTransform(double scale)
|
||||
{
|
||||
return BuildScaleTransform(scale, 1.0);
|
||||
}
|
||||
|
||||
protected TransformOperations BuildScaleYTransform(double scale)
|
||||
protected static TransformOperations BuildScaleYTransform(double scale)
|
||||
{
|
||||
return BuildScaleTransform(1.0, scale);
|
||||
}
|
||||
|
||||
protected TransformOperations BuildTranslateTransform(double offsetX, double offsetY)
|
||||
protected static TransformOperations BuildTranslateTransform(double offsetX, double offsetY)
|
||||
{
|
||||
var builder = new TransformOperations.Builder(1);
|
||||
builder.AppendTranslate(offsetX, offsetY);
|
||||
return builder.Build();
|
||||
}
|
||||
|
||||
protected static TransformOperations BuildTranslateScaleAndTransform(
|
||||
double scaleX, double scaleY, double offsetX, double offsetY)
|
||||
{
|
||||
var builder = new TransformOperations.Builder(2);
|
||||
builder.AppendScale(scaleX, scaleY);
|
||||
builder.AppendTranslate(offsetX, offsetY);
|
||||
return builder.Build();
|
||||
}
|
||||
|
||||
protected Animation CreateAnimation()
|
||||
{
|
||||
var animation = new Animation
|
||||
{
|
||||
Duration = Duration,
|
||||
Easing = Easing,
|
||||
FillMode = PropertyValueFillMode
|
||||
};
|
||||
return animation;
|
||||
}
|
||||
}
|
@ -1,139 +0,0 @@
|
||||
using Avalonia.Animation.Easings;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Layout;
|
||||
|
||||
namespace AtomUI.MotionScene;
|
||||
|
||||
public class CollapseMotion : AbstractMotion
|
||||
{
|
||||
public MotionConfig? OpacityConfig => GetMotionConfig(MotionOpacityProperty);
|
||||
public MotionConfig? HeightConfig => GetMotionConfig(MotionHeightProperty);
|
||||
|
||||
/// <summary>
|
||||
/// 收起的方向,垂直还是水平方向
|
||||
/// </summary>
|
||||
public Orientation Orientation { get; set; } = Orientation.Vertical;
|
||||
|
||||
public void ConfigureHeight(TimeSpan duration, Easing? easing = null)
|
||||
{
|
||||
easing ??= new CubicEaseInOut();
|
||||
var config = new MotionConfig(Orientation == Orientation.Vertical
|
||||
? MotionHeightProperty
|
||||
: MotionWidthProperty)
|
||||
{
|
||||
TransitionKind = TransitionKind.Double,
|
||||
EndValue = 0d,
|
||||
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);
|
||||
}
|
||||
|
||||
protected override void NotifyPreBuildTransition(MotionConfig config, Control motionTarget)
|
||||
{
|
||||
base.NotifyPreBuildTransition(config, motionTarget);
|
||||
if (config.Property == MotionHeightProperty)
|
||||
{
|
||||
if (!double.IsNaN(motionTarget.Height))
|
||||
{
|
||||
config.StartValue = Math.Ceiling(motionTarget.Height);
|
||||
}
|
||||
else
|
||||
{
|
||||
config.StartValue = Math.Ceiling(motionTarget.DesiredSize.Height);
|
||||
}
|
||||
}
|
||||
else if (config.Property == MotionWidthProperty)
|
||||
{
|
||||
if (!double.IsNaN(motionTarget.Width))
|
||||
{
|
||||
config.StartValue = Math.Ceiling(motionTarget.Width);
|
||||
}
|
||||
else
|
||||
{
|
||||
config.StartValue = Math.Ceiling(motionTarget.DesiredSize.Width);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ExpandMotion : AbstractMotion
|
||||
{
|
||||
public MotionConfig? OpacityConfig => GetMotionConfig(MotionOpacityProperty);
|
||||
public MotionConfig? HeightConfig => GetMotionConfig(MotionHeightProperty);
|
||||
|
||||
/// <summary>
|
||||
/// 展开的方向,垂直还是水平方向
|
||||
/// </summary>
|
||||
public Orientation Orientation { get; set; } = Orientation.Vertical;
|
||||
|
||||
public void ConfigureHeight(TimeSpan duration, Easing? easing = null)
|
||||
{
|
||||
easing ??= new CubicEaseInOut();
|
||||
var config = new MotionConfig(Orientation == Orientation.Vertical
|
||||
? MotionHeightProperty
|
||||
: MotionWidthProperty)
|
||||
{
|
||||
TransitionKind = TransitionKind.Double,
|
||||
StartValue = 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 = 0d,
|
||||
EndValue = 1d,
|
||||
MotionDuration = duration,
|
||||
MotionEasing = easing
|
||||
};
|
||||
AddMotionConfig(config);
|
||||
}
|
||||
|
||||
protected override void NotifyPreBuildTransition(MotionConfig config, Control motionTarget)
|
||||
{
|
||||
base.NotifyPreBuildTransition(config, motionTarget);
|
||||
if (config.Property == MotionHeightProperty)
|
||||
{
|
||||
if (!double.IsNaN(motionTarget.Height))
|
||||
{
|
||||
config.EndValue = Math.Ceiling(motionTarget.Height);
|
||||
}
|
||||
else
|
||||
{
|
||||
config.EndValue = Math.Ceiling(motionTarget.DesiredSize.Height);
|
||||
}
|
||||
}
|
||||
else if (config.Property == MotionWidthProperty)
|
||||
{
|
||||
if (!double.IsNaN(motionTarget.Width))
|
||||
{
|
||||
config.EndValue = Math.Ceiling(motionTarget.Width);
|
||||
}
|
||||
else
|
||||
{
|
||||
config.EndValue = Math.Ceiling(motionTarget.DesiredSize.Width);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
212
src/AtomUI.Base/MotionScene/CollapseMotions.cs
Normal file
212
src/AtomUI.Base/MotionScene/CollapseMotions.cs
Normal file
@ -0,0 +1,212 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Animation;
|
||||
using Avalonia.Animation.Easings;
|
||||
using Avalonia.Styling;
|
||||
|
||||
namespace AtomUI.MotionScene;
|
||||
|
||||
internal class CollapseMotion : AbstractMotion
|
||||
{
|
||||
public Direction Direction { get; }
|
||||
|
||||
public CollapseMotion(Direction direction,
|
||||
TimeSpan duration,
|
||||
Easing? easing = null,
|
||||
FillMode fillMode = FillMode.None)
|
||||
: base(duration, easing ?? new CubicEaseOut(), fillMode)
|
||||
{
|
||||
Direction = direction;
|
||||
}
|
||||
|
||||
protected override void Configure()
|
||||
{
|
||||
var isHorizontal = Direction == Direction.Left || Direction == Direction.Right;
|
||||
var animation = CreateAnimation();
|
||||
|
||||
var startFrame = new KeyFrame
|
||||
{
|
||||
Cue = new Cue(0.0)
|
||||
};
|
||||
{
|
||||
var opacitySetter = new Setter
|
||||
{
|
||||
Property = Visual.OpacityProperty,
|
||||
Value = 1.0
|
||||
};
|
||||
startFrame.Setters.Add(opacitySetter);
|
||||
if (isHorizontal)
|
||||
{
|
||||
var scaleXSetter = new Setter
|
||||
{
|
||||
Property = MotionActorControl.MotionTransformProperty,
|
||||
Value = BuildScaleXTransform(1.0)
|
||||
};
|
||||
startFrame.Setters.Add(scaleXSetter);
|
||||
}
|
||||
else
|
||||
{
|
||||
var scaleYSetter = new Setter
|
||||
{
|
||||
Property = MotionActorControl.MotionTransformProperty,
|
||||
Value = BuildScaleYTransform(1.0)
|
||||
};
|
||||
startFrame.Setters.Add(scaleYSetter);
|
||||
}
|
||||
}
|
||||
animation.Children.Add(startFrame);
|
||||
|
||||
var endFrame = new KeyFrame
|
||||
{
|
||||
Cue = new Cue(1.0)
|
||||
};
|
||||
{
|
||||
var opacitySetter = new Setter
|
||||
{
|
||||
Property = Visual.OpacityProperty,
|
||||
Value = 0.0
|
||||
};
|
||||
endFrame.Setters.Add(opacitySetter);
|
||||
if (isHorizontal)
|
||||
{
|
||||
var scaleXSetter = new Setter
|
||||
{
|
||||
Property = MotionActorControl.MotionTransformProperty,
|
||||
Value = BuildScaleXTransform(0.0)
|
||||
};
|
||||
endFrame.Setters.Add(scaleXSetter);
|
||||
}
|
||||
else
|
||||
{
|
||||
var scaleYSetter = new Setter
|
||||
{
|
||||
Property = MotionActorControl.MotionTransformProperty,
|
||||
Value = BuildScaleYTransform(0.0)
|
||||
};
|
||||
endFrame.Setters.Add(scaleYSetter);
|
||||
}
|
||||
}
|
||||
animation.Children.Add(endFrame);
|
||||
|
||||
if (Direction == Direction.Left)
|
||||
{
|
||||
RenderTransformOrigin = new RelativePoint(1, 0.5, RelativeUnit.Relative);
|
||||
}
|
||||
else if (Direction == Direction.Right)
|
||||
{
|
||||
RenderTransformOrigin = new RelativePoint(0, 0.5, RelativeUnit.Relative);
|
||||
}
|
||||
else if (Direction == Direction.Top)
|
||||
{
|
||||
RenderTransformOrigin = new RelativePoint(0.5, 1.0, RelativeUnit.Relative);
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderTransformOrigin = new RelativePoint(0.5, 0.0, RelativeUnit.Relative);
|
||||
}
|
||||
|
||||
Animations.Add(animation);
|
||||
}
|
||||
}
|
||||
|
||||
internal class ExpandMotion : AbstractMotion
|
||||
{
|
||||
public Direction Direction { get; }
|
||||
|
||||
public ExpandMotion(Direction direction,
|
||||
TimeSpan duration,
|
||||
Easing? easing = null,
|
||||
FillMode fillMode = FillMode.None)
|
||||
: base(duration, easing ?? new CubicEaseIn(), fillMode)
|
||||
{
|
||||
Direction = direction;
|
||||
}
|
||||
|
||||
protected override void Configure()
|
||||
{
|
||||
var isHorizontal = Direction == Direction.Left || Direction == Direction.Right;
|
||||
var animation = CreateAnimation();
|
||||
var startFrame = new KeyFrame
|
||||
{
|
||||
Cue = new Cue(0.0)
|
||||
};
|
||||
{
|
||||
var opacitySetter = new Setter
|
||||
{
|
||||
Property = Visual.OpacityProperty,
|
||||
Value = 0.0
|
||||
};
|
||||
startFrame.Setters.Add(opacitySetter);
|
||||
if (isHorizontal)
|
||||
{
|
||||
var scaleXSetter = new Setter
|
||||
{
|
||||
Property = MotionActorControl.MotionTransformProperty,
|
||||
Value = BuildScaleXTransform(0.01)
|
||||
};
|
||||
startFrame.Setters.Add(scaleXSetter);
|
||||
}
|
||||
else
|
||||
{
|
||||
var scaleYSetter = new Setter
|
||||
{
|
||||
Property = MotionActorControl.MotionTransformProperty,
|
||||
Value = BuildScaleYTransform(0.01)
|
||||
};
|
||||
startFrame.Setters.Add(scaleYSetter);
|
||||
}
|
||||
}
|
||||
animation.Children.Add(startFrame);
|
||||
|
||||
var endFrame = new KeyFrame
|
||||
{
|
||||
Cue = new Cue(1.0)
|
||||
};
|
||||
{
|
||||
var opacitySetter = new Setter
|
||||
{
|
||||
Property = Visual.OpacityProperty,
|
||||
Value = 1.0
|
||||
};
|
||||
endFrame.Setters.Add(opacitySetter);
|
||||
if (isHorizontal)
|
||||
{
|
||||
var scaleXSetter = new Setter
|
||||
{
|
||||
Property = MotionActorControl.MotionTransformProperty,
|
||||
Value = BuildScaleXTransform(1.0)
|
||||
};
|
||||
endFrame.Setters.Add(scaleXSetter);
|
||||
}
|
||||
else
|
||||
{
|
||||
var scaleYSetter = new Setter
|
||||
{
|
||||
Property = MotionActorControl.MotionTransformProperty,
|
||||
Value = BuildScaleYTransform(1.0)
|
||||
};
|
||||
endFrame.Setters.Add(scaleYSetter);
|
||||
}
|
||||
}
|
||||
|
||||
animation.Children.Add(endFrame);
|
||||
|
||||
if (Direction == Direction.Left)
|
||||
{
|
||||
RenderTransformOrigin = new RelativePoint(1.0, 0.5, RelativeUnit.Relative);
|
||||
}
|
||||
else if (Direction == Direction.Right)
|
||||
{
|
||||
RenderTransformOrigin = new RelativePoint(0.0, 0.5, RelativeUnit.Relative);
|
||||
}
|
||||
else if (Direction == Direction.Top)
|
||||
{
|
||||
RenderTransformOrigin = new RelativePoint(0.5, 1.0, RelativeUnit.Relative);
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderTransformOrigin = new RelativePoint(0.5, 1.0, RelativeUnit.Relative);
|
||||
}
|
||||
|
||||
Animations.Add(animation);
|
||||
}
|
||||
}
|
@ -1,17 +1,20 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Animation;
|
||||
using Avalonia.Animation.Easings;
|
||||
|
||||
namespace AtomUI.MotionScene;
|
||||
|
||||
public interface IMotion
|
||||
internal interface IMotion
|
||||
{
|
||||
public bool IsRunning { get; }
|
||||
public RelativePoint RenderTransformOrigin { get; }
|
||||
public IList<Animation> Animations { get; }
|
||||
public TimeSpan Duration { get; }
|
||||
public Easing Easing { get; }
|
||||
public FillMode PropertyValueFillMode { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前动效激活的动画属性列表
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IList<AvaloniaProperty> GetActivatedProperties();
|
||||
|
||||
public IList<MotionConfig> GetMotionConfigs();
|
||||
public IObservable<bool>? CompletedObservable { get; }
|
||||
public Task RunAsync(MotionActorControl actor,
|
||||
Action? aboutToStart = null,
|
||||
Action? completedAction = null,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
Loading…
Reference in New Issue
Block a user