mirror of
https://gitee.com/chinware/atomui.git
synced 2024-11-29 18:38:16 +08:00
Add Motion for Expander Control
This commit is contained in:
parent
b6fcc74be3
commit
8a2092cc0f
@ -310,7 +310,6 @@ public class CollapseItem : HeaderedContentControl, ISelectable
|
||||
InAnimating = true;
|
||||
var slideDownInMotionConfig = MotionFactory.BuildSlideUpInMotion(MotionDuration, new CubicEaseOut(),
|
||||
FillMode.Forward);
|
||||
_motionActor.RenderTransformOrigin = slideDownInMotionConfig.RenderTransformOrigin;
|
||||
MotionInvoker.Invoke(_motionActor, slideDownInMotionConfig, () =>
|
||||
{
|
||||
_motionActor.SetCurrentValue(IsVisibleProperty, true);
|
||||
|
@ -1,9 +1,11 @@
|
||||
using AtomUI.Controls.Utils;
|
||||
using AtomUI.MotionScene;
|
||||
using AtomUI.Controls.Primitives;
|
||||
using AtomUI.Controls.Utils;
|
||||
using AtomUI.Theme.Data;
|
||||
using AtomUI.Theme.Styling;
|
||||
using AtomUI.Utils;
|
||||
using Avalonia;
|
||||
using Avalonia.Animation;
|
||||
using Avalonia.Animation.Easings;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Controls.Templates;
|
||||
@ -162,14 +164,16 @@ public class Expander : AvaloniaExpander
|
||||
|
||||
#endregion
|
||||
|
||||
private AnimationTargetPanel? _animationTarget;
|
||||
private MotionActorControl? _motionActor;
|
||||
private Border? _headerDecorator;
|
||||
private IconButton? _expandButton;
|
||||
private bool _animating;
|
||||
private bool _enableAnimation = true;
|
||||
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
base.OnApplyTemplate(e);
|
||||
_animationTarget = e.NameScope.Find<AnimationTargetPanel>(ExpanderTheme.ContentAnimationTargetPart);
|
||||
_motionActor = e.NameScope.Find<MotionActorControl>(ExpanderTheme.ContentMotionActorPart);
|
||||
_headerDecorator = e.NameScope.Find<Border>(ExpanderTheme.HeaderDecoratorPart);
|
||||
_expandButton = e.NameScope.Find<IconButton>(ExpanderTheme.ExpandButtonPart);
|
||||
TokenResourceBinder.CreateTokenBinding(this, MotionDurationProperty, GlobalTokenResourceKey.MotionDurationSlow);
|
||||
@ -179,10 +183,19 @@ public class Expander : AvaloniaExpander
|
||||
SetupEffectiveBorderThickness();
|
||||
SetupExpanderBorderThickness();
|
||||
SetupIconButton();
|
||||
_enableAnimation = false;
|
||||
HandleExpandedChanged();
|
||||
_enableAnimation = true;
|
||||
if (_expandButton is not null)
|
||||
{
|
||||
_expandButton.Click += (sender, args) => { IsExpanded = !IsExpanded; };
|
||||
_expandButton.Click += (sender, args) =>
|
||||
{
|
||||
if (_animating)
|
||||
{
|
||||
return;
|
||||
}
|
||||
IsExpanded = !IsExpanded;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -277,6 +290,10 @@ public class Expander : AvaloniaExpander
|
||||
var targetRect = new Rect(_headerDecorator.Bounds.Size);
|
||||
if (targetRect.Contains(position))
|
||||
{
|
||||
if (_animating)
|
||||
{
|
||||
return;
|
||||
}
|
||||
IsExpanded = !IsExpanded;
|
||||
}
|
||||
}
|
||||
@ -285,17 +302,76 @@ public class Expander : AvaloniaExpander
|
||||
|
||||
private void HandleExpandedChanged()
|
||||
{
|
||||
if (_animationTarget is not null)
|
||||
if (IsExpanded)
|
||||
{
|
||||
if (IsExpanded)
|
||||
{
|
||||
_animationTarget.IsVisible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_animationTarget.IsVisible = false;
|
||||
}
|
||||
ExpandItemContent();
|
||||
}
|
||||
else
|
||||
{
|
||||
CollapseItemContent();
|
||||
}
|
||||
}
|
||||
|
||||
private void ExpandItemContent()
|
||||
{
|
||||
if (_motionActor is null || _animating)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_enableAnimation)
|
||||
{
|
||||
_motionActor.IsVisible = true;
|
||||
return;
|
||||
}
|
||||
|
||||
_animating = true;
|
||||
var expandMotionConfig = MotionFactory.BuildExpandMotion(DirectionFromExpandDirection(ExpandDirection),
|
||||
MotionDuration,
|
||||
new CubicEaseOut(),
|
||||
FillMode.Forward);
|
||||
MotionInvoker.Invoke(_motionActor, expandMotionConfig, () =>
|
||||
{
|
||||
_motionActor.SetCurrentValue(IsVisibleProperty, true);
|
||||
}, () =>
|
||||
{
|
||||
_animating = false;
|
||||
});
|
||||
}
|
||||
|
||||
private void CollapseItemContent()
|
||||
{
|
||||
if (_motionActor is null || _animating)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!_enableAnimation)
|
||||
{
|
||||
_motionActor.IsVisible = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_animating = true;
|
||||
var slideDownOutMotionConfig = MotionFactory.BuildCollapseMotion(DirectionFromExpandDirection(ExpandDirection),
|
||||
MotionDuration,
|
||||
new CubicEaseIn(),
|
||||
FillMode.Forward);
|
||||
MotionInvoker.Invoke(_motionActor, slideDownOutMotionConfig, null, () =>
|
||||
{
|
||||
_motionActor.SetCurrentValue(IsVisibleProperty, false);
|
||||
_animating = false;
|
||||
});
|
||||
}
|
||||
|
||||
private static Direction DirectionFromExpandDirection(ExpandDirection expandDirection)
|
||||
{
|
||||
return expandDirection switch
|
||||
{
|
||||
ExpandDirection.Left => Direction.Left,
|
||||
ExpandDirection.Up => Direction.Top,
|
||||
ExpandDirection.Right => Direction.Right,
|
||||
ExpandDirection.Down => Direction.Bottom,
|
||||
};
|
||||
}
|
||||
|
||||
private void SetupEffectiveBorderThickness()
|
||||
|
@ -1,4 +1,4 @@
|
||||
using AtomUI.MotionScene;
|
||||
using AtomUI.Controls.Primitives;
|
||||
using AtomUI.Theme;
|
||||
using AtomUI.Theme.Styling;
|
||||
using AtomUI.Theme.Utils;
|
||||
@ -30,7 +30,7 @@ internal class ExpanderTheme : BaseControlTheme
|
||||
public const string HeaderDecoratorPart = "PART_HeaderDecorator";
|
||||
public const string ContentPresenterPart = "PART_ContentPresenter";
|
||||
public const string AddOnContentPresenterPart = "PART_AddOnContentPresenter";
|
||||
public const string ContentAnimationTargetPart = "PART_ContentAnimationTarget";
|
||||
public const string ContentMotionActorPart = "PART_ContentMotionActor";
|
||||
|
||||
public ExpanderTheme() : base(typeof(Expander))
|
||||
{
|
||||
@ -56,17 +56,17 @@ internal class ExpanderTheme : BaseControlTheme
|
||||
};
|
||||
|
||||
BuildHeader(mainLayout, scope);
|
||||
var animationPanel = new AnimationTargetPanel
|
||||
var motionActor = new MotionActorControl()
|
||||
{
|
||||
Name = ContentAnimationTargetPart,
|
||||
Name = ContentMotionActorPart,
|
||||
ClipToBounds = true
|
||||
};
|
||||
var contentPresenter = new ContentPresenter
|
||||
{
|
||||
Name = ContentPresenterPart
|
||||
};
|
||||
animationPanel.SetCurrentValue(Visual.IsVisibleProperty, false);
|
||||
animationPanel.Children.Add(contentPresenter);
|
||||
motionActor.SetCurrentValue(Visual.IsVisibleProperty, false);
|
||||
motionActor.Child = contentPresenter;
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(contentPresenter, ContentPresenter.BorderBrushProperty,
|
||||
GlobalTokenResourceKey.ColorBorder);
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.ContentProperty,
|
||||
@ -74,8 +74,8 @@ internal class ExpanderTheme : BaseControlTheme
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.ContentTemplateProperty,
|
||||
ContentControl.ContentTemplateProperty);
|
||||
|
||||
mainLayout.Children.Add(animationPanel);
|
||||
animationPanel.RegisterInNameScope(scope);
|
||||
mainLayout.Children.Add(motionActor);
|
||||
motionActor.RegisterInNameScope(scope);
|
||||
contentPresenter.RegisterInNameScope(scope);
|
||||
|
||||
frameDecorator.Child = mainLayout;
|
||||
|
@ -201,7 +201,6 @@ public class MessageCard : TemplatedControl
|
||||
_motionActor.IsVisible = false;
|
||||
var moveUpInMotionConfig = MotionFactory.BuildMoveUpInMotion(AnimationMaxOffsetY, _openCloseMotionDuration, new CubicEaseOut(),
|
||||
FillMode.Forward);
|
||||
_motionActor.RenderTransformOrigin = moveUpInMotionConfig.RenderTransformOrigin;
|
||||
MotionInvoker.Invoke(_motionActor, moveUpInMotionConfig, () =>
|
||||
{
|
||||
_motionActor.IsVisible = true;
|
||||
@ -215,7 +214,6 @@ public class MessageCard : TemplatedControl
|
||||
{
|
||||
var moveUpOutMotionConfig = MotionFactory.BuildMoveUpOutMotion(AnimationMaxOffsetY, _openCloseMotionDuration, new CubicEaseIn(),
|
||||
FillMode.Forward);
|
||||
_motionActor.RenderTransformOrigin = moveUpOutMotionConfig.RenderTransformOrigin;
|
||||
MotionInvoker.Invoke(_motionActor, moveUpOutMotionConfig, null, () =>
|
||||
{
|
||||
IsClosed = true;
|
||||
|
@ -1080,7 +1080,6 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
||||
_animating = true;
|
||||
var slideDownInMotionConfig = MotionFactory.BuildSlideUpInMotion(_openCloseMotionDuration, new CubicEaseOut(),
|
||||
FillMode.Forward);
|
||||
_childItemsLayoutTransform.RenderTransformOrigin = slideDownInMotionConfig.RenderTransformOrigin;
|
||||
MotionInvoker.Invoke(_childItemsLayoutTransform, slideDownInMotionConfig, () =>
|
||||
{
|
||||
_childItemsLayoutTransform.SetCurrentValue(IsVisibleProperty, true);
|
||||
|
@ -264,7 +264,6 @@ public class NotificationCard : ContentControl
|
||||
}
|
||||
|
||||
_motionActor.IsVisible = false;
|
||||
_motionActor.RenderTransformOrigin = motionConfig.RenderTransformOrigin;
|
||||
MotionInvoker.Invoke(_motionActor, motionConfig, () =>
|
||||
{
|
||||
_motionActor.IsVisible = true;
|
||||
@ -299,7 +298,6 @@ public class NotificationCard : ContentControl
|
||||
FillMode.Forward);
|
||||
}
|
||||
|
||||
_motionActor.RenderTransformOrigin = motionConfig.RenderTransformOrigin;
|
||||
MotionInvoker.Invoke(_motionActor, motionConfig, null, () =>
|
||||
{
|
||||
IsClosed = true;
|
||||
|
@ -215,7 +215,10 @@ public class MotionActorControl : Decorator
|
||||
}
|
||||
|
||||
// Perform a measure on the MotionTransformRoot (containing Child)
|
||||
MotionTransformRoot.Measure(measureSize);
|
||||
if (MotionTransformRoot.DesiredSize == default)
|
||||
{
|
||||
MotionTransformRoot.Measure(measureSize);
|
||||
}
|
||||
|
||||
var desiredSize = MotionTransformRoot.DesiredSize;
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Animation;
|
||||
using Avalonia.Animation.Easings;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Styling;
|
||||
|
||||
namespace AtomUI.Controls.Utils;
|
||||
@ -12,7 +11,7 @@ internal static partial class MotionFactory
|
||||
public static MotionConfig BuildCollapseMotion(Direction direction, TimeSpan duration, Easing? easing = null,
|
||||
FillMode fillMode = FillMode.None)
|
||||
{
|
||||
easing ??= new CircularEaseOut();
|
||||
easing ??= new CubicEaseOut();
|
||||
var animations = new List<Animation>();
|
||||
RelativePoint transformOrigin = default;
|
||||
var isHorizontal = direction == Direction.Left || direction == Direction.Right;
|
||||
@ -85,22 +84,23 @@ internal static partial class MotionFactory
|
||||
endFrame.Setters.Add(scaleYSetter);
|
||||
}
|
||||
}
|
||||
animation.Children.Add(endFrame);
|
||||
|
||||
if (direction == Direction.Left)
|
||||
{
|
||||
transformOrigin = new RelativePoint(0, 0.5, RelativeUnit.Relative);
|
||||
transformOrigin = new RelativePoint(1, 0.5, RelativeUnit.Relative);
|
||||
}
|
||||
else if (direction == Direction.Right)
|
||||
{
|
||||
transformOrigin = new RelativePoint(1, 0.5, RelativeUnit.Relative);
|
||||
transformOrigin = new RelativePoint(0, 0.5, RelativeUnit.Relative);
|
||||
}
|
||||
else if (direction == Direction.Top)
|
||||
{
|
||||
transformOrigin = new RelativePoint(0.5, 0, RelativeUnit.Relative);
|
||||
transformOrigin = new RelativePoint(0.5, 1.0, RelativeUnit.Relative);
|
||||
}
|
||||
else
|
||||
{
|
||||
transformOrigin = new RelativePoint(0.5, 1, RelativeUnit.Relative);
|
||||
transformOrigin = new RelativePoint(0.5, 0.0, RelativeUnit.Relative);
|
||||
}
|
||||
|
||||
animations.Add(animation);
|
||||
@ -110,7 +110,7 @@ internal static partial class MotionFactory
|
||||
public static MotionConfig BuildExpandMotion(Direction direction, TimeSpan duration, Easing? easing = null,
|
||||
FillMode fillMode = FillMode.None)
|
||||
{
|
||||
easing ??= new CircularEaseOut();
|
||||
easing ??= new CubicEaseIn();
|
||||
var animations = new List<Animation>();
|
||||
RelativePoint transformOrigin = default;
|
||||
var isHorizontal = direction == Direction.Left || direction == Direction.Right;
|
||||
@ -183,22 +183,24 @@ internal static partial class MotionFactory
|
||||
endFrame.Setters.Add(scaleYSetter);
|
||||
}
|
||||
}
|
||||
|
||||
animation.Children.Add(endFrame);
|
||||
|
||||
if (direction == Direction.Left)
|
||||
{
|
||||
transformOrigin = new RelativePoint(0, 0.5, RelativeUnit.Relative);
|
||||
transformOrigin = new RelativePoint(1.0, 0.5, RelativeUnit.Relative);
|
||||
}
|
||||
else if (direction == Direction.Right)
|
||||
{
|
||||
transformOrigin = new RelativePoint(1, 0.5, RelativeUnit.Relative);
|
||||
transformOrigin = new RelativePoint(0.0, 0.5, RelativeUnit.Relative);
|
||||
}
|
||||
else if (direction == Direction.Top)
|
||||
{
|
||||
transformOrigin = new RelativePoint(0.5, 0, RelativeUnit.Relative);
|
||||
transformOrigin = new RelativePoint(0.5, 1.0, RelativeUnit.Relative);
|
||||
}
|
||||
else
|
||||
{
|
||||
transformOrigin = new RelativePoint(0.5, 1, RelativeUnit.Relative);
|
||||
transformOrigin = new RelativePoint(0.5, 1.0, RelativeUnit.Relative);
|
||||
}
|
||||
|
||||
animations.Add(animation);
|
||||
|
@ -2,8 +2,6 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Animation;
|
||||
using Avalonia.Animation.Easings;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Media.Transformation;
|
||||
using Avalonia.Styling;
|
||||
|
||||
namespace AtomUI.Controls.Utils;
|
||||
|
Loading…
Reference in New Issue
Block a user