Refactor Message And Notificatioon Motion

This commit is contained in:
polarboy 2024-09-29 17:36:37 +08:00
parent 4a26c737eb
commit 4a98f6d5be
9 changed files with 330 additions and 598 deletions

View File

@ -1,7 +1,12 @@
using AtomUI.Icon;
using AtomUI.Controls.Primitives;
using AtomUI.Controls.Utils;
using AtomUI.Icon;
using AtomUI.Theme.Styling;
using AtomUI.Utils;
using Avalonia;
using Avalonia.Animation;
using Avalonia.Animation.Easings;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
@ -16,6 +21,8 @@ public class MessageCard : TemplatedControl
public const string SuccessPC = ":success";
public const string WarningPC = ":warning";
public const string LoadingPC = ":loading";
internal const double AnimationMaxOffsetY = 100d;
#region
@ -99,7 +106,24 @@ public class MessageCard : TemplatedControl
#endregion
#region
internal static readonly DirectProperty<MessageCard, TimeSpan> OpenCloseMotionDurationProperty =
AvaloniaProperty.RegisterDirect<MessageCard, TimeSpan>(nameof(OpenCloseMotionDuration),
o => o.OpenCloseMotionDuration,
(o, v) => o.OpenCloseMotionDuration = v);
private TimeSpan _openCloseMotionDuration;
internal TimeSpan OpenCloseMotionDuration
{
get => _openCloseMotionDuration;
set => SetAndRaise(OpenCloseMotionDurationProperty, ref _openCloseMotionDuration, value);
}
#endregion
private bool _isClosing;
private MotionActorControl? _motionActor;
/// <summary>
/// Initializes a new instance of the <see cref="MessageCard" /> class.
@ -147,6 +171,14 @@ public class MessageCard : TemplatedControl
RaiseEvent(new RoutedEventArgs(MessageClosedEvent));
}
if (e.Property == IsClosingProperty)
{
if (IsClosing)
{
ApplyHideMotion();
}
}
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
@ -157,8 +189,40 @@ public class MessageCard : TemplatedControl
SetupMessageIcon();
UpdateMessageType();
}
TokenResourceBinder.CreateGlobalTokenBinding(this, OpenCloseMotionDurationProperty, GlobalTokenResourceKey.MotionDurationMid);
_motionActor = e.NameScope.Find<MotionActorControl>(MessageCardTheme.MotionActorPart);
ApplyShowMotion();
}
private void ApplyShowMotion()
{
if (_motionActor is not null)
{
_motionActor.IsVisible = false;
var moveUpInMotionConfig = MotionFactory.BuildMoveUpInMotion(AnimationMaxOffsetY, _openCloseMotionDuration, new CubicEaseOut(),
FillMode.Forward);
_motionActor.RenderTransformOrigin = moveUpInMotionConfig.RenderTransformOrigin;
MotionInvoker.Invoke(_motionActor, moveUpInMotionConfig, () =>
{
_motionActor.IsVisible = true;
});
}
}
private void ApplyHideMotion()
{
if (_motionActor is not null)
{
var moveUpOutMotionConfig = MotionFactory.BuildMoveUpOutMotion(AnimationMaxOffsetY, _openCloseMotionDuration, new CubicEaseIn(),
FillMode.Forward);
_motionActor.RenderTransformOrigin = moveUpOutMotionConfig.RenderTransformOrigin;
MotionInvoker.Invoke(_motionActor, moveUpOutMotionConfig, null, () =>
{
IsClosed = true;
});
}
}
private void UpdateMessageType()
{
switch (MessageType)

View File

@ -1,4 +1,4 @@
using AtomUI.Controls.Utils;
using AtomUI.Controls.Primitives;
using AtomUI.Theme;
using AtomUI.Theme.Styling;
using AtomUI.Utils;
@ -22,15 +22,9 @@ internal class MessageCardTheme : BaseControlTheme
public const string IconContentPart = "PART_IconContent";
public const string HeaderContainerPart = "PART_HeaderContainer";
public const string MessagePart = "PART_Message";
public const string LayoutTransformControlPart = "PART_LayoutTransformControl";
public const string MotionActorPart = "PART_MotionActor";
public const string MarginGhostDecoratorPart = "PART_MarginGhostDecorator";
public const double AnimationMaxOffsetY = 100d;
public const int AnimationDuration = 400;
private readonly Easing _quadraticEaseOut = new QuadraticEaseOut();
private readonly Easing _quadraticEaseIn = new QuadraticEaseIn();
public MessageCardTheme()
: base(typeof(MessageCard))
{
@ -41,12 +35,12 @@ internal class MessageCardTheme : BaseControlTheme
return new FuncControlTemplate<MessageCard>((card, scope) =>
{
BuildInstanceStyles(card);
var layoutTransformControl = new LayoutTransformControl
var motionActor = new MotionActorControl()
{
Name = LayoutTransformControlPart,
Name = MotionActorPart,
ClipToBounds = false
};
layoutTransformControl.RegisterInNameScope(scope);
motionActor.RegisterInNameScope(scope);
// 防止关闭的时候抖动,如果直接设置到 MessageCardlayoutTransformControl没有办法平滑处理
var marginGhostDecorator = new Border
@ -67,8 +61,8 @@ internal class MessageCardTheme : BaseControlTheme
frameDecorator.RegisterInNameScope(scope);
layoutTransformControl.Child = marginGhostDecorator;
return layoutTransformControl;
motionActor.Child = marginGhostDecorator;
return motionActor;
});
}
@ -112,7 +106,6 @@ internal class MessageCardTheme : BaseControlTheme
BuildCommonStyle();
BuildContentStyle();
BuildContentStyle();
BuildAnimationStyle();
}
private void BuildCommonStyle()
@ -157,61 +150,4 @@ internal class MessageCardTheme : BaseControlTheme
iconStyle.Add(Layoutable.HeightProperty, MessageTokenResourceKey.MessageIconSize);
control.Styles.Add(iconStyle);
}
private void BuildAnimationStyle()
{
var commonStyle = new Style(selector => selector.Nesting());
{
var layoutTransformStyle =
new Style(selector => selector.Nesting().Template().Name(LayoutTransformControlPart));
var moveRightInMotionConfig = MotionFactory.BuildMoveUpInMotion(
AnimationMaxOffsetY, TimeSpan.FromMilliseconds(AnimationDuration), _quadraticEaseOut,
FillMode.Forward);
foreach (var animation in moveRightInMotionConfig.Animations)
{
layoutTransformStyle.Animations.Add(animation);
}
commonStyle.Add(layoutTransformStyle);
}
var isClosingStyle =
new Style(selector => selector.Nesting().PropertyEquals(MessageCard.IsClosingProperty, true));
{
var layoutTransformStyle =
new Style(selector => selector.Nesting().Template().Name(LayoutTransformControlPart));
var moveRightOutMotionConfig = MotionFactory.BuildMoveUpOutMotion(
AnimationMaxOffsetY, TimeSpan.FromMilliseconds(AnimationDuration), _quadraticEaseIn, FillMode.Forward);
foreach (var animation in moveRightOutMotionConfig.Animations)
{
layoutTransformStyle.Animations.Add(animation);
}
isClosingStyle.Animations.Add(new Animation
{
Duration = TimeSpan.FromMilliseconds(AnimationDuration * 1.2),
Easing = _quadraticEaseIn,
FillMode = FillMode.Forward,
Children =
{
new KeyFrame
{
Cue = new Cue(1.0),
Setters =
{
new Setter(MessageCard.IsClosedProperty, true)
}
}
}
});
isClosingStyle.Add(layoutTransformStyle);
}
commonStyle.Add(isClosingStyle);
Add(commonStyle);
}
}

View File

@ -467,8 +467,6 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
ItemsPanelProperty.OverrideDefaultValue<NavMenuItem>(DefaultPanel);
ClickEvent.AddClassHandler<NavMenuItem>((x, e) => x.OnClick(e));
SubmenuOpenedEvent.AddClassHandler<NavMenuItem>((x, e) => x.OnSubmenuOpened(e));
Animation.RegisterCustomAnimator<TransformOperations, MotionTransformOptionsAnimator>();
}
public NavMenuItem()
@ -1103,7 +1101,6 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
}
_animating = true;
SetCurrentValue(IsSubMenuOpenProperty, false);
var slideDownOutMotionConfig = MotionFactory.BuildSlideUpOutMotion(_openCloseMotionDuration, new CubicEaseIn(),
FillMode.Forward);
MotionInvoker.Invoke(_childItemsLayoutTransform, slideDownOutMotionConfig, null, () =>

View File

@ -1,6 +1,10 @@
using AtomUI.Theme.Styling;
using AtomUI.Controls.Primitives;
using AtomUI.Controls.Utils;
using AtomUI.Theme.Styling;
using AtomUI.Utils;
using Avalonia;
using Avalonia.Animation;
using Avalonia.Animation.Easings;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
@ -17,6 +21,9 @@ public class NotificationCard : ContentControl
public const string InformationPC = ":information";
public const string SuccessPC = ":success";
public const string WarningPC = ":warning";
internal const double AnimationMaxOffsetY = 150d;
internal const double AnimationMaxOffsetX = 500d;
#region
@ -121,6 +128,11 @@ public class NotificationCard : ContentControl
nameof(Position),
o => o.Position,
(o, v) => o.Position = v);
internal static readonly DirectProperty<NotificationCard, TimeSpan> OpenCloseMotionDurationProperty =
AvaloniaProperty.RegisterDirect<NotificationCard, TimeSpan>(nameof(OpenCloseMotionDuration),
o => o.OpenCloseMotionDuration,
(o, v) => o.OpenCloseMotionDuration = v);
private bool _effectiveShowProgress;
@ -138,8 +150,15 @@ public class NotificationCard : ContentControl
set => SetAndRaise(PositionProperty, ref _position, value);
}
private TimeSpan _openCloseMotionDuration;
internal TimeSpan OpenCloseMotionDuration
{
get => _openCloseMotionDuration;
set => SetAndRaise(OpenCloseMotionDurationProperty, ref _openCloseMotionDuration, value);
}
#endregion
/// <summary>
/// Gets the expiration time of the notification after which it will automatically close.
/// If the value is null then the notification will remain open until the user closes it.
@ -150,6 +169,7 @@ public class NotificationCard : ContentControl
private NotificationProgressBar? _progressBar;
private readonly WindowNotificationManager _notificationManager;
private IconButton? _closeButton;
private MotionActorControl? _motionActor;
/// <summary>
/// Initializes a new instance of the <see cref="NotificationCard" /> class.
@ -188,9 +208,11 @@ public class NotificationCard : ContentControl
SetupNotificationIcon();
UpdateNotificationType();
}
TokenResourceBinder.CreateGlobalTokenBinding(this, OpenCloseMotionDurationProperty, GlobalTokenResourceKey.MotionDurationMid);
_progressBar = e.NameScope.Find<NotificationProgressBar>(NotificationCardTheme.ProgressBarPart);
_closeButton = e.NameScope.Find<IconButton>(NotificationCardTheme.CloseButtonPart);
_motionActor = e.NameScope.Find<MotionActorControl>(NotificationCardTheme.MotionActorPart);
if (_progressBar is not null)
{
if (Expiration is null)
@ -209,6 +231,79 @@ public class NotificationCard : ContentControl
}
SetupEffectiveShowProgress();
ApplyShowMotion();
}
private void ApplyShowMotion()
{
if (_motionActor is null)
{
return;
}
MotionConfig? motionConfig;
if (Position == NotificationPosition.TopLeft || Position == NotificationPosition.BottomLeft)
{
motionConfig = MotionFactory.BuildMoveLeftInMotion(AnimationMaxOffsetX, _openCloseMotionDuration, new CubicEaseOut(),
FillMode.Forward);
}
else if (Position == NotificationPosition.TopRight || Position == NotificationPosition.BottomRight)
{
motionConfig = MotionFactory.BuildMoveRightInMotion(AnimationMaxOffsetX, _openCloseMotionDuration, new CubicEaseOut(),
FillMode.Forward);
}
else if (Position == NotificationPosition.TopCenter)
{
motionConfig = MotionFactory.BuildMoveUpInMotion(AnimationMaxOffsetY, _openCloseMotionDuration, new CubicEaseOut(),
FillMode.Forward);
}
else
{
motionConfig = MotionFactory.BuildMoveDownInMotion(AnimationMaxOffsetY, _openCloseMotionDuration, new CubicEaseOut(),
FillMode.Forward);
}
_motionActor.IsVisible = false;
_motionActor.RenderTransformOrigin = motionConfig.RenderTransformOrigin;
MotionInvoker.Invoke(_motionActor, motionConfig, () =>
{
_motionActor.IsVisible = true;
});
}
private void ApplyHideMotion()
{
if (_motionActor is null)
{
return;
}
MotionConfig? motionConfig;
if (Position == NotificationPosition.TopLeft || Position == NotificationPosition.BottomLeft)
{
motionConfig = MotionFactory.BuildMoveLeftOutMotion(AnimationMaxOffsetX, _openCloseMotionDuration, new CubicEaseIn(),
FillMode.Forward);
}
else if (Position == NotificationPosition.TopRight || Position == NotificationPosition.BottomRight)
{
motionConfig = MotionFactory.BuildMoveRightOutMotion(AnimationMaxOffsetX, _openCloseMotionDuration, new CubicEaseIn(),
FillMode.Forward);
}
else if (Position == NotificationPosition.TopCenter)
{
motionConfig = MotionFactory.BuildMoveUpOutMotion(AnimationMaxOffsetY, _openCloseMotionDuration, new CubicEaseIn(),
FillMode.Forward);
}
else
{
motionConfig = MotionFactory.BuildMoveDownOutMotion(AnimationMaxOffsetY, _openCloseMotionDuration, new CubicEaseIn(),
FillMode.Forward);
}
_motionActor.RenderTransformOrigin = motionConfig.RenderTransformOrigin;
MotionInvoker.Invoke(_motionActor, motionConfig, null, () =>
{
IsClosed = true;
});
}
private void HandleCloseButtonClose(object? sender, EventArgs args)
@ -254,6 +349,14 @@ public class NotificationCard : ContentControl
{
UpdatePseudoClasses(e.GetNewValue<NotificationPosition>());
}
if (e.Property == IsClosingProperty)
{
if (IsClosing)
{
ApplyHideMotion();
}
}
}
private void SetupEffectiveShowProgress()

View File

@ -1,4 +1,5 @@
using AtomUI.Controls.Utils;
using AtomUI.Controls.Primitives;
using AtomUI.Controls.Utils;
using AtomUI.Theme;
using AtomUI.Theme.Styling;
using AtomUI.Utils;
@ -26,16 +27,10 @@ internal class NotificationCardTheme : BaseControlTheme
public const string HeaderTitlePart = "PART_HeaderTitle";
public const string ContentPart = "PART_Content";
public const string CloseButtonPart = "PART_CloseButton";
public const string LayoutTransformControlPart = "PART_LayoutTransformControl";
public const string MotionActorPart = "PART_MotionActor";
public const string ProgressBarPart = "PART_ProgressBar";
public const string MarginGhostDecoratorPart = "PART_MarginGhostDecorator";
public const double AnimationMaxOffsetY = 150d;
public const double AnimationMaxOffsetX = 500d;
public const int AnimationDuration = 400;
private readonly Easing _quadraticEaseOut = new QuadraticEaseOut();
private readonly Easing _quadraticEaseIn = new QuadraticEaseIn();
public NotificationCardTheme()
: base(typeof(NotificationCard))
@ -47,12 +42,12 @@ internal class NotificationCardTheme : BaseControlTheme
return new FuncControlTemplate<NotificationCard>((card, scope) =>
{
BuildInstanceStyles(card);
var layoutTransformControl = new LayoutTransformControl
var motionActor = new MotionActorControl()
{
Name = LayoutTransformControlPart,
Name = MotionActorPart,
ClipToBounds = false
};
layoutTransformControl.RegisterInNameScope(scope);
motionActor.RegisterInNameScope(scope);
// 防止关闭的时候抖动,如果直接设置到 NotificationCardlayoutTransformControl没有办法平滑处理
var marginGhostDecorator = new Border
@ -88,8 +83,8 @@ internal class NotificationCardTheme : BaseControlTheme
BuildProgressBar(mainLayout, scope);
frameDecorator.RegisterInNameScope(scope);
layoutTransformControl.Child = marginGhostDecorator;
return layoutTransformControl;
motionActor.Child = marginGhostDecorator;
return motionActor;
});
}
@ -209,7 +204,6 @@ internal class NotificationCardTheme : BaseControlTheme
BuildCommonStyle();
BuildHeaderStyle();
BuildContentStyle();
BuildAnimationStyle();
}
private void BuildCommonStyle()
@ -329,252 +323,4 @@ internal class NotificationCardTheme : BaseControlTheme
iconStyle.Add(Layoutable.HeightProperty, NotificationTokenResourceKey.NotificationIconSize);
control.Styles.Add(iconStyle);
}
private void BuildAnimationStyle()
{
var commonStyle = new Style(selector => selector.Nesting());
var topLeftStyle = new Style(selector =>
selector.Nesting().PropertyEquals(NotificationCard.PositionProperty, NotificationPosition.TopLeft));
BuildLeftEdgeAnimation(topLeftStyle);
commonStyle.Add(topLeftStyle);
var topCenterStyle = new Style(selector =>
selector.Nesting().PropertyEquals(NotificationCard.PositionProperty, NotificationPosition.TopCenter));
commonStyle.Add(topCenterStyle);
BuildTopCenterEdgeAnimation(topCenterStyle);
var topRightStyle = new Style(selector =>
selector.Nesting().PropertyEquals(NotificationCard.PositionProperty, NotificationPosition.TopRight));
commonStyle.Add(topRightStyle);
BuildRightEdgeAnimation(topRightStyle);
var bottomLeftStyle = new Style(selector =>
selector.Nesting().PropertyEquals(NotificationCard.PositionProperty, NotificationPosition.BottomLeft));
BuildLeftEdgeAnimation(bottomLeftStyle);
commonStyle.Add(bottomLeftStyle);
var bottomCenterStyle = new Style(selector =>
selector.Nesting().PropertyEquals(NotificationCard.PositionProperty, NotificationPosition.BottomCenter));
BuildBottomCenterEdgeAnimation(bottomCenterStyle);
commonStyle.Add(bottomCenterStyle);
var bottomRightStyle = new Style(selector =>
selector.Nesting().PropertyEquals(NotificationCard.PositionProperty, NotificationPosition.BottomRight));
BuildRightEdgeAnimation(bottomRightStyle);
commonStyle.Add(bottomRightStyle);
Add(commonStyle);
}
private void BuildRightEdgeAnimation(Style parentStyle)
{
{
var layoutTransformStyle =
new Style(selector => selector.Nesting().Template().Name(LayoutTransformControlPart));
var moveRightInMotionConfig = MotionFactory.BuildMoveRightInMotion(AnimationMaxOffsetX,
TimeSpan.FromMilliseconds(AnimationDuration), _quadraticEaseOut,
FillMode.Forward);
foreach (var animation in moveRightInMotionConfig.Animations)
{
layoutTransformStyle.Animations.Add(animation);
}
parentStyle.Add(layoutTransformStyle);
}
var isClosingStyle = new Style(selector =>
selector.Nesting().PropertyEquals(NotificationCard.IsClosingProperty, true));
{
var layoutTransformStyle =
new Style(selector => selector.Nesting().Template().Name(LayoutTransformControlPart));
var moveRightOutMotionConfig = MotionFactory.BuildMoveRightOutMotion(AnimationMaxOffsetX,
TimeSpan.FromMilliseconds(AnimationDuration), _quadraticEaseIn, FillMode.Forward);
foreach (var animation in moveRightOutMotionConfig.Animations)
{
layoutTransformStyle.Animations.Add(animation);
}
isClosingStyle.Animations.Add(new Animation
{
Duration = TimeSpan.FromMilliseconds(AnimationDuration * 1.2),
Easing = _quadraticEaseIn,
FillMode = FillMode.Forward,
Children =
{
new KeyFrame
{
Cue = new Cue(1.0),
Setters =
{
new Setter(NotificationCard.IsClosedProperty, true)
}
}
}
});
isClosingStyle.Add(layoutTransformStyle);
}
parentStyle.Add(isClosingStyle);
}
private void BuildLeftEdgeAnimation(Style parentStyle)
{
{
var layoutTransformStyle =
new Style(selector => selector.Nesting().Template().Name(LayoutTransformControlPart));
var moveLeftInMotionConfig = MotionFactory.BuildMoveLeftInMotion(AnimationMaxOffsetX,
TimeSpan.FromMilliseconds(AnimationDuration), _quadraticEaseOut,
FillMode.Forward);
foreach (var animation in moveLeftInMotionConfig.Animations)
{
layoutTransformStyle.Animations.Add(animation);
}
parentStyle.Add(layoutTransformStyle);
}
var isClosingStyle = new Style(selector =>
selector.Nesting().PropertyEquals(NotificationCard.IsClosingProperty, true));
{
var layoutTransformStyle =
new Style(selector => selector.Nesting().Template().Name(LayoutTransformControlPart));
var moveRightOutMotionConfig = MotionFactory.BuildMoveLeftOutMotion(AnimationMaxOffsetX,
TimeSpan.FromMilliseconds(AnimationDuration), _quadraticEaseIn, FillMode.Forward);
foreach (var animation in moveRightOutMotionConfig.Animations)
{
layoutTransformStyle.Animations.Add(animation);
}
isClosingStyle.Animations.Add(new Animation
{
Duration = TimeSpan.FromMilliseconds(AnimationDuration * 1.2),
Easing = _quadraticEaseIn,
FillMode = FillMode.Forward,
Children =
{
new KeyFrame
{
Cue = new Cue(1.0),
Setters =
{
new Setter(NotificationCard.IsClosedProperty, true)
}
}
}
});
isClosingStyle.Add(layoutTransformStyle);
}
parentStyle.Add(isClosingStyle);
}
private void BuildTopCenterEdgeAnimation(Style parentStyle)
{
{
var layoutTransformStyle =
new Style(selector => selector.Nesting().Template().Name(LayoutTransformControlPart));
var moveRightInMotionConfig = MotionFactory.BuildMoveUpInMotion(AnimationMaxOffsetY,
TimeSpan.FromMilliseconds(AnimationDuration), _quadraticEaseOut,
FillMode.Forward);
foreach (var animation in moveRightInMotionConfig.Animations)
{
layoutTransformStyle.Animations.Add(animation);
}
parentStyle.Add(layoutTransformStyle);
}
var isClosingStyle = new Style(selector =>
selector.Nesting().PropertyEquals(NotificationCard.IsClosingProperty, true));
{
var layoutTransformStyle =
new Style(selector => selector.Nesting().Template().Name(LayoutTransformControlPart));
var moveRightOutMotionConfig = MotionFactory.BuildMoveUpOutMotion(AnimationMaxOffsetY,
TimeSpan.FromMilliseconds(AnimationDuration), _quadraticEaseIn, FillMode.Forward);
foreach (var animation in moveRightOutMotionConfig.Animations)
{
layoutTransformStyle.Animations.Add(animation);
}
isClosingStyle.Animations.Add(new Animation
{
Duration = TimeSpan.FromMilliseconds(AnimationDuration * 1.2),
Easing = _quadraticEaseIn,
FillMode = FillMode.Forward,
Children =
{
new KeyFrame
{
Cue = new Cue(1.0),
Setters =
{
new Setter(NotificationCard.IsClosedProperty, true)
}
}
}
});
isClosingStyle.Add(layoutTransformStyle);
}
parentStyle.Add(isClosingStyle);
}
private void BuildBottomCenterEdgeAnimation(Style parentStyle)
{
{
var layoutTransformStyle =
new Style(selector => selector.Nesting().Template().Name(LayoutTransformControlPart));
var moveRightInMotionConfig = MotionFactory.BuildMoveDownInMotion(AnimationMaxOffsetY,
TimeSpan.FromMilliseconds(AnimationDuration), _quadraticEaseOut,
FillMode.Forward);
foreach (var animation in moveRightInMotionConfig.Animations)
{
layoutTransformStyle.Animations.Add(animation);
}
parentStyle.Add(layoutTransformStyle);
}
var isClosingStyle = new Style(selector =>
selector.Nesting().PropertyEquals(NotificationCard.IsClosingProperty, true));
{
var layoutTransformStyle =
new Style(selector => selector.Nesting().Template().Name(LayoutTransformControlPart));
var moveRightOutMotionConfig = MotionFactory.BuildMoveDownOutMotion(AnimationMaxOffsetY,
TimeSpan.FromMilliseconds(AnimationDuration), _quadraticEaseIn, FillMode.Forward);
foreach (var animation in moveRightOutMotionConfig.Animations)
{
layoutTransformStyle.Animations.Add(animation);
}
isClosingStyle.Animations.Add(new Animation
{
Duration = TimeSpan.FromMilliseconds(AnimationDuration * 1.2),
Easing = _quadraticEaseIn,
FillMode = FillMode.Forward,
Children =
{
new KeyFrame
{
Cue = new Cue(1.0),
Setters =
{
new Setter(NotificationCard.IsClosedProperty, true)
}
}
}
});
isClosingStyle.Add(layoutTransformStyle);
}
parentStyle.Add(isClosingStyle);
}
}

View File

@ -87,7 +87,6 @@ public class MotionActorControl : Decorator
MotionTransformRoot.RenderTransform = _matrixTransform;
MotionTransformRoot.RenderTransformOrigin = new RelativePoint(0, 0, RelativeUnit.Absolute);
}
ApplyMotionTransform();
}
@ -111,6 +110,7 @@ public class MotionActorControl : Decorator
_transformation = matrix;
_matrixTransform.Matrix = FilterScaleTransform(matrix);
RenderTransform = _matrixTransform;
// New transform means re-layout is necessary
InvalidateMeasure();
}

View File

@ -1,5 +1,8 @@
using AtomUI.Theme;
using AtomUI.Controls.Utils;
using AtomUI.Theme;
using Avalonia;
using Avalonia.Animation;
using Avalonia.Media.Transformation;
namespace AtomUI.Controls;
@ -7,6 +10,7 @@ internal static class ThemeManagerExtensions
{
public static ThemeManager ConfigureAtomUIControls(this ThemeManager themeManager)
{
Animation.RegisterCustomAnimator<TransformOperations, MotionTransformOptionsAnimator>();
AvaloniaLocator.CurrentMutable.BindToSelf(new ToolTipService());
ControlThemeRegister.Register();
ControlTokenTypeRegister.Register();

View File

@ -46,4 +46,12 @@ internal static partial class MotionFactory
builder.AppendTranslate(offsetX, offsetY);
return builder.Build();
}
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();
}
}

View File

@ -1,4 +1,5 @@
using Avalonia;
using AtomUI.Controls.Primitives;
using Avalonia;
using Avalonia.Animation;
using Avalonia.Animation.Easings;
using Avalonia.Media;
@ -8,7 +9,9 @@ namespace AtomUI.Controls.Utils;
internal static partial class MotionFactory
{
public static MotionConfig BuildMoveDownInMotion(double offset, TimeSpan duration, Easing? easing = null,
public static MotionConfig BuildMoveDownInMotion(double offset,
TimeSpan duration,
Easing? easing = null,
FillMode fillMode = FillMode.None)
{
easing ??= new QuinticEaseOut();
@ -33,25 +36,18 @@ internal static partial class MotionFactory
};
startFrame.Setters.Add(opacitySetter);
var translateYSetter = new Setter
var transformSetter = new Setter
{
Property = TranslateTransform.YProperty,
Value = offset
Property = MotionActorControl.MotionTransformProperty,
Value = BuildTranslateScaleAndTransform(1.0, 0.01, 0.0, offset)
};
startFrame.Setters.Add(translateYSetter);
var scaleYSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 0.0
};
startFrame.Setters.Add(scaleYSetter);
startFrame.Setters.Add(transformSetter);
}
animation.Children.Add(startFrame);
var middleFrame = new KeyFrame
{
Cue = new Cue(0.6)
Cue = new Cue(0.8)
};
{
var opacitySetter = new Setter
@ -60,18 +56,13 @@ internal static partial class MotionFactory
Value = 0.1
};
middleFrame.Setters.Add(opacitySetter);
var translateYSetter = new Setter
var transformSetter = new Setter
{
Property = TranslateTransform.YProperty,
Value = offset / 4
Property = MotionActorControl.MotionTransformProperty,
Value = BuildTranslateScaleAndTransform(1.0, 1.0, 0.0, offset / 4)
};
middleFrame.Setters.Add(translateYSetter);
var scaleYSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 1.0
};
middleFrame.Setters.Add(scaleYSetter);
middleFrame.Setters.Add(transformSetter);
}
animation.Children.Add(middleFrame);
@ -86,19 +77,13 @@ internal static partial class MotionFactory
Value = 1.0
};
endFrame.Setters.Add(opacitySetter);
var translateYSetter = new Setter
{
Property = TranslateTransform.YProperty,
Value = 0.0
};
endFrame.Setters.Add(translateYSetter);
var scaleYSetter = new Setter
var transformSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 1.0
Property = MotionActorControl.MotionTransformProperty,
Value = BuildTranslateScaleAndTransform(1.0, 1.0, 0.0, 0.0)
};
endFrame.Setters.Add(scaleYSetter);
endFrame.Setters.Add(transformSetter);
}
animation.Children.Add(endFrame);
transformOrigin = new RelativePoint(0.0, 0.0, RelativeUnit.Relative);
@ -107,7 +92,9 @@ internal static partial class MotionFactory
return new MotionConfig(transformOrigin, animations);
}
public static MotionConfig BuildMoveDownOutMotion(double offset, TimeSpan duration, Easing? easing = null,
public static MotionConfig BuildMoveDownOutMotion(double offset,
TimeSpan duration,
Easing? easing = null,
FillMode fillMode = FillMode.None)
{
easing ??= new QuinticEaseIn();
@ -132,45 +119,34 @@ internal static partial class MotionFactory
};
startFrame.Setters.Add(opacitySetter);
var translateYSetter = new Setter
var transformSetter = new Setter
{
Property = TranslateTransform.YProperty,
Value = 0.0
Property = MotionActorControl.MotionTransformProperty,
Value = BuildTranslateScaleAndTransform(1.0, 1.0, 0.0, 0.0)
};
startFrame.Setters.Add(translateYSetter);
var scaleYSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 1.0
};
startFrame.Setters.Add(scaleYSetter);
startFrame.Setters.Add(transformSetter);
}
animation.Children.Add(startFrame);
var middleFrame = new KeyFrame
{
Cue = new Cue(0.35)
Cue = new Cue(0.8)
};
{
var opacitySetter = new Setter
{
Property = Visual.OpacityProperty,
Value = 0.0
Value = 0.1
};
middleFrame.Setters.Add(opacitySetter);
var translateYSetter = new Setter
var transformSetter = new Setter
{
Property = TranslateTransform.YProperty,
Value = offset / 2
Property = MotionActorControl.MotionTransformProperty,
Value = BuildTranslateScaleAndTransform(1.0, 1.0, 0.0, offset / 4)
};
middleFrame.Setters.Add(translateYSetter);
var scaleYSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 1.0
};
middleFrame.Setters.Add(scaleYSetter);
middleFrame.Setters.Add(transformSetter);
}
animation.Children.Add(middleFrame);
@ -185,19 +161,13 @@ internal static partial class MotionFactory
Value = 0.0
};
endFrame.Setters.Add(opacitySetter);
var translateYSetter = new Setter
{
Property = TranslateTransform.YProperty,
Value = offset
};
endFrame.Setters.Add(translateYSetter);
var scaleYSetter = new Setter
var transformSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 0.0
Property = MotionActorControl.MotionTransformProperty,
Value = BuildTranslateScaleAndTransform(1.0, 0.0, 0.0, offset)
};
endFrame.Setters.Add(scaleYSetter);
endFrame.Setters.Add(transformSetter);
}
animation.Children.Add(endFrame);
transformOrigin = new RelativePoint(0, 0, RelativeUnit.Relative);
@ -231,25 +201,18 @@ internal static partial class MotionFactory
};
startFrame.Setters.Add(opacitySetter);
var translateYSetter = new Setter
var transformSetter = new Setter
{
Property = TranslateTransform.YProperty,
Value = -offset
Property = MotionActorControl.MotionTransformProperty,
Value = BuildTranslateScaleAndTransform(1.0, 0.01, 0.0, -offset)
};
startFrame.Setters.Add(translateYSetter);
var scaleYSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 0.0
};
startFrame.Setters.Add(scaleYSetter);
startFrame.Setters.Add(transformSetter);
}
animation.Children.Add(startFrame);
var middleFrame = new KeyFrame
{
Cue = new Cue(0.6)
Cue = new Cue(0.8)
};
{
var opacitySetter = new Setter
@ -258,18 +221,13 @@ internal static partial class MotionFactory
Value = 0.1
};
middleFrame.Setters.Add(opacitySetter);
var translateYSetter = new Setter
var transformSetter = new Setter
{
Property = TranslateTransform.YProperty,
Value = -offset / 4
Property = MotionActorControl.MotionTransformProperty,
Value = BuildTranslateScaleAndTransform(1.0, 1.0, 0.0, -offset / 4)
};
middleFrame.Setters.Add(translateYSetter);
var scaleYSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 1.0
};
middleFrame.Setters.Add(scaleYSetter);
middleFrame.Setters.Add(transformSetter);
}
animation.Children.Add(middleFrame);
@ -284,19 +242,13 @@ internal static partial class MotionFactory
Value = 1.0
};
endFrame.Setters.Add(opacitySetter);
var translateYSetter = new Setter
{
Property = TranslateTransform.YProperty,
Value = 0.0
};
endFrame.Setters.Add(translateYSetter);
var scaleYSetter = new Setter
var transformSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 1.0
Property = MotionActorControl.MotionTransformProperty,
Value = BuildTranslateScaleAndTransform(1.0, 1.0, 0.0, 0.0)
};
endFrame.Setters.Add(scaleYSetter);
endFrame.Setters.Add(transformSetter);
}
animation.Children.Add(endFrame);
transformOrigin = new RelativePoint(0.0, 0.0, RelativeUnit.Relative);
@ -337,38 +289,35 @@ internal static partial class MotionFactory
};
startFrame.Setters.Add(translateYSetter);
var scaleYSetter = new Setter
var transformSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 1.0
Property = MotionActorControl.MotionTransformProperty,
Value = BuildTranslateScaleAndTransform(1.0, 1.0, 0.0, 0.0)
};
startFrame.Setters.Add(scaleYSetter);
startFrame.Setters.Add(transformSetter);
}
animation.Children.Add(startFrame);
var middleFrame = new KeyFrame
{
Cue = new Cue(0.35)
Cue = new Cue(0.8)
};
{
var opacitySetter = new Setter
{
Property = Visual.OpacityProperty,
Value = 0.0
Value = 0.1
};
middleFrame.Setters.Add(opacitySetter);
var translateYSetter = new Setter
var transformSetter = new Setter
{
Property = TranslateTransform.YProperty,
Value = -offset / 2
Property = MotionActorControl.MotionTransformProperty,
Value = BuildTranslateScaleAndTransform(1.0, 1.0, 0.0, -offset / 4)
};
middleFrame.Setters.Add(translateYSetter);
var scaleYSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 1.0
};
middleFrame.Setters.Add(scaleYSetter);
middleFrame.Setters.Add(transformSetter);
}
animation.Children.Add(middleFrame);
@ -383,19 +332,14 @@ internal static partial class MotionFactory
Value = 0.0
};
endFrame.Setters.Add(opacitySetter);
var translateYSetter = new Setter
{
Property = TranslateTransform.YProperty,
Value = -offset
};
endFrame.Setters.Add(translateYSetter);
var scaleYSetter = new Setter
var transformSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 0.0
Property = MotionActorControl.MotionTransformProperty,
Value = BuildTranslateScaleAndTransform(1.0, 0.0, 0.0, -offset)
};
endFrame.Setters.Add(scaleYSetter);
endFrame.Setters.Add(transformSetter);
}
animation.Children.Add(endFrame);
transformOrigin = new RelativePoint(0, 0, RelativeUnit.Relative);
@ -429,45 +373,35 @@ internal static partial class MotionFactory
};
startFrame.Setters.Add(opacitySetter);
var translateXSetter = new Setter
var transformSetter = new Setter
{
Property = TranslateTransform.XProperty,
Value = -offset
Property = MotionActorControl.MotionTransformProperty,
Value = BuildTranslateScaleAndTransform(1.0, 0.01, -offset, 0.0)
};
startFrame.Setters.Add(translateXSetter);
var scaleYSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 0.0
};
startFrame.Setters.Add(scaleYSetter);
startFrame.Setters.Add(transformSetter);
}
animation.Children.Add(startFrame);
var middleFrame = new KeyFrame
{
Cue = new Cue(0.7)
Cue = new Cue(0.8)
};
{
var opacitySetter = new Setter
{
Property = Visual.OpacityProperty,
Value = 0.0
Value = 0.1
};
middleFrame.Setters.Add(opacitySetter);
var translateXSetter = new Setter
var transformSetter = new Setter
{
Property = TranslateTransform.XProperty,
Value = -offset
Property = MotionActorControl.MotionTransformProperty,
Value = BuildTranslateScaleAndTransform(1.0, 1.0, -offset / 2, 0.0)
};
middleFrame.Setters.Add(translateXSetter);
var scaleYSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 1.0
};
middleFrame.Setters.Add(scaleYSetter);
middleFrame.Setters.Add(transformSetter);
}
animation.Children.Add(middleFrame);
@ -482,19 +416,14 @@ internal static partial class MotionFactory
Value = 1.0
};
endFrame.Setters.Add(opacitySetter);
var translateXSetter = new Setter
{
Property = TranslateTransform.XProperty,
Value = 0.0
};
endFrame.Setters.Add(translateXSetter);
var scaleYSetter = new Setter
var transformSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 1.0
Property = MotionActorControl.MotionTransformProperty,
Value = BuildTranslateScaleAndTransform(1.0, 1.0, 0.0, 0.0)
};
endFrame.Setters.Add(scaleYSetter);
endFrame.Setters.Add(transformSetter);
}
animation.Children.Add(endFrame);
transformOrigin = new RelativePoint(0.0, 0.0, RelativeUnit.Relative);
@ -528,45 +457,32 @@ internal static partial class MotionFactory
};
startFrame.Setters.Add(opacitySetter);
var translateXSetter = new Setter
var transformSetter = new Setter
{
Property = TranslateTransform.XProperty,
Value = 0.0
Property = MotionActorControl.MotionTransformProperty,
Value = BuildTranslateScaleAndTransform(1.0, 1.0, 0.0, 0.0)
};
startFrame.Setters.Add(translateXSetter);
var scaleYSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 1.0
};
startFrame.Setters.Add(scaleYSetter);
startFrame.Setters.Add(transformSetter);
}
animation.Children.Add(startFrame);
var middleFrame = new KeyFrame
{
Cue = new Cue(0.75)
Cue = new Cue(0.8)
};
{
var opacitySetter = new Setter
{
Property = Visual.OpacityProperty,
Value = 1.0
Value = 0.1
};
middleFrame.Setters.Add(opacitySetter);
var translateXSetter = new Setter
var transformSetter = new Setter
{
Property = TranslateTransform.XProperty,
Value = -offset
Property = MotionActorControl.MotionTransformProperty,
Value = BuildTranslateScaleAndTransform(1.0, 1.0, -offset / 2, 0.0)
};
middleFrame.Setters.Add(translateXSetter);
var scaleYSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 1.0
};
middleFrame.Setters.Add(scaleYSetter);
middleFrame.Setters.Add(transformSetter);
}
animation.Children.Add(middleFrame);
@ -581,19 +497,13 @@ internal static partial class MotionFactory
Value = 0.0
};
endFrame.Setters.Add(opacitySetter);
var translateXSetter = new Setter
{
Property = TranslateTransform.XProperty,
Value = -offset
};
endFrame.Setters.Add(translateXSetter);
var scaleYSetter = new Setter
var transformSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 0.0
Property = MotionActorControl.MotionTransformProperty,
Value = BuildTranslateScaleAndTransform(1.0, 0.0, -offset, 0.0)
};
endFrame.Setters.Add(scaleYSetter);
endFrame.Setters.Add(transformSetter);
}
animation.Children.Add(endFrame);
transformOrigin = new RelativePoint(0, 0, RelativeUnit.Relative);
@ -627,45 +537,33 @@ internal static partial class MotionFactory
};
startFrame.Setters.Add(opacitySetter);
var translateXSetter = new Setter
var transformSetter = new Setter
{
Property = TranslateTransform.XProperty,
Value = offset
Property = MotionActorControl.MotionTransformProperty,
Value = BuildTranslateScaleAndTransform(1.0, 0.01, offset, 0.0)
};
startFrame.Setters.Add(translateXSetter);
var scaleYSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 0.0
};
startFrame.Setters.Add(scaleYSetter);
startFrame.Setters.Add(transformSetter);
}
animation.Children.Add(startFrame);
var middleFrame = new KeyFrame
{
Cue = new Cue(0.7)
Cue = new Cue(0.8)
};
{
var opacitySetter = new Setter
{
Property = Visual.OpacityProperty,
Value = 0.0
Value = 0.1
};
middleFrame.Setters.Add(opacitySetter);
var translateXSetter = new Setter
var transformSetter = new Setter
{
Property = TranslateTransform.XProperty,
Value = offset
Property = MotionActorControl.MotionTransformProperty,
Value = BuildTranslateScaleAndTransform(1.0, 1.0, offset / 2, 0.0)
};
middleFrame.Setters.Add(translateXSetter);
var scaleYSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 1.0
};
middleFrame.Setters.Add(scaleYSetter);
middleFrame.Setters.Add(transformSetter);
}
animation.Children.Add(middleFrame);
@ -680,19 +578,13 @@ internal static partial class MotionFactory
Value = 1.0
};
endFrame.Setters.Add(opacitySetter);
var translateXSetter = new Setter
{
Property = TranslateTransform.XProperty,
Value = 0.0
};
endFrame.Setters.Add(translateXSetter);
var scaleYSetter = new Setter
var transformSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 1.0
Property = MotionActorControl.MotionTransformProperty,
Value = BuildTranslateScaleAndTransform(1.0, 1.0, 0.0, 0.0)
};
endFrame.Setters.Add(scaleYSetter);
endFrame.Setters.Add(transformSetter);
}
animation.Children.Add(endFrame);
transformOrigin = new RelativePoint(0.0, 0.0, RelativeUnit.Relative);
@ -726,25 +618,18 @@ internal static partial class MotionFactory
};
startFrame.Setters.Add(opacitySetter);
var translateXSetter = new Setter
var transformSetter = new Setter
{
Property = TranslateTransform.XProperty,
Value = 0.0
Property = MotionActorControl.MotionTransformProperty,
Value = BuildTranslateScaleAndTransform(1.0, 1.0, 0.0, 0.0)
};
startFrame.Setters.Add(translateXSetter);
var scaleYSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 1.0
};
startFrame.Setters.Add(scaleYSetter);
startFrame.Setters.Add(transformSetter);
}
animation.Children.Add(startFrame);
var middleFrame = new KeyFrame
{
Cue = new Cue(0.75)
Cue = new Cue(0.8)
};
{
var opacitySetter = new Setter
@ -753,18 +638,13 @@ internal static partial class MotionFactory
Value = 1.0
};
middleFrame.Setters.Add(opacitySetter);
var translateXSetter = new Setter
var transformSetter = new Setter
{
Property = TranslateTransform.XProperty,
Value = offset
Property = MotionActorControl.MotionTransformProperty,
Value = BuildTranslateScaleAndTransform(1.0, 1.0, offset / 2, 0.0)
};
middleFrame.Setters.Add(translateXSetter);
var scaleYSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 1.0
};
middleFrame.Setters.Add(scaleYSetter);
middleFrame.Setters.Add(transformSetter);
}
animation.Children.Add(middleFrame);
@ -779,19 +659,13 @@ internal static partial class MotionFactory
Value = 0.0
};
endFrame.Setters.Add(opacitySetter);
var translateXSetter = new Setter
{
Property = TranslateTransform.XProperty,
Value = offset
};
endFrame.Setters.Add(translateXSetter);
var scaleYSetter = new Setter
var transformSetter = new Setter
{
Property = ScaleTransform.ScaleYProperty,
Value = 0.0
Property = MotionActorControl.MotionTransformProperty,
Value = BuildTranslateScaleAndTransform(1.0, 0.0, offset, 0.0)
};
endFrame.Setters.Add(scaleYSetter);
endFrame.Setters.Add(transformSetter);
}
animation.Children.Add(endFrame);
transformOrigin = new RelativePoint(0, 0, RelativeUnit.Relative);