mirror of
https://gitee.com/chinware/atomui.git
synced 2024-11-29 18:38:16 +08:00
Merge branch 'develop' of https://gitee.com/chinware/atomui into develop
This commit is contained in:
commit
d604d2aec3
@ -1,14 +1,13 @@
|
||||
using AtomUI.Controls.Primitives;
|
||||
using Avalonia;
|
||||
using Avalonia;
|
||||
using Avalonia.Animation;
|
||||
using Avalonia.Animation.Easings;
|
||||
using Avalonia.Styling;
|
||||
|
||||
namespace AtomUI.Controls.Utils;
|
||||
namespace AtomUI.MotionScene;
|
||||
|
||||
internal static partial class MotionFactory
|
||||
{
|
||||
public static MotionConfig BuildCollapseMotion(Direction direction, TimeSpan duration, Easing? easing = null,
|
||||
public static MotionConfigX BuildCollapseMotion(Direction direction, TimeSpan duration, Easing? easing = null,
|
||||
FillMode fillMode = FillMode.None)
|
||||
{
|
||||
easing ??= new CubicEaseOut();
|
||||
@ -104,10 +103,10 @@ internal static partial class MotionFactory
|
||||
}
|
||||
|
||||
animations.Add(animation);
|
||||
return new MotionConfig(transformOrigin, animations);
|
||||
return new MotionConfigX(transformOrigin, animations);
|
||||
}
|
||||
|
||||
public static MotionConfig BuildExpandMotion(Direction direction, TimeSpan duration, Easing? easing = null,
|
||||
public static MotionConfigX BuildExpandMotion(Direction direction, TimeSpan duration, Easing? easing = null,
|
||||
FillMode fillMode = FillMode.None)
|
||||
{
|
||||
easing ??= new CubicEaseIn();
|
||||
@ -183,7 +182,7 @@ internal static partial class MotionFactory
|
||||
endFrame.Setters.Add(scaleYSetter);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
animation.Children.Add(endFrame);
|
||||
|
||||
if (direction == Direction.Left)
|
||||
@ -204,6 +203,6 @@ internal static partial class MotionFactory
|
||||
}
|
||||
|
||||
animations.Add(animation);
|
||||
return new MotionConfig(transformOrigin, animations);
|
||||
return new MotionConfigX(transformOrigin, animations);
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ using Avalonia.Controls;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Media.Transformation;
|
||||
|
||||
namespace AtomUI.Controls.Primitives;
|
||||
namespace AtomUI.MotionScene;
|
||||
|
||||
public class MotionActorControl : Decorator
|
||||
{
|
||||
@ -12,6 +12,9 @@ public class MotionActorControl : Decorator
|
||||
|
||||
public static readonly StyledProperty<TransformOperations?> MotionTransformProperty =
|
||||
AvaloniaProperty.Register<MotionActorControl, TransformOperations?>(nameof(MotionTransform));
|
||||
|
||||
public static readonly StyledProperty<bool> UseRenderTransformProperty =
|
||||
AvaloniaProperty.Register<LayoutTransformControl, bool>(nameof(UseRenderTransform));
|
||||
|
||||
public TransformOperations? MotionTransform
|
||||
{
|
||||
@ -19,6 +22,12 @@ public class MotionActorControl : Decorator
|
||||
set => SetValue(MotionTransformProperty, value);
|
||||
}
|
||||
|
||||
public bool UseRenderTransform
|
||||
{
|
||||
get => GetValue(UseRenderTransformProperty);
|
||||
set => SetValue(UseRenderTransformProperty, value);
|
||||
}
|
||||
|
||||
public Control? MotionTransformRoot => Child;
|
||||
|
||||
#endregion
|
||||
@ -107,9 +116,9 @@ public class MotionActorControl : Decorator
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
_transformation = matrix;
|
||||
_matrixTransform.Matrix = FilterScaleTransform(matrix);
|
||||
_matrixTransform.Matrix = UseRenderTransform ? matrix : FilterScaleTransform(matrix);
|
||||
RenderTransform = _matrixTransform;
|
||||
// New transform means re-layout is necessary
|
||||
InvalidateMeasure();
|
||||
@ -145,15 +154,15 @@ public class MotionActorControl : Decorator
|
||||
|
||||
protected override Size ArrangeOverride(Size finalSize)
|
||||
{
|
||||
if (MotionTransformRoot == null || MotionTransform == null)
|
||||
if (MotionTransformRoot == null || MotionTransform == null || UseRenderTransform)
|
||||
{
|
||||
// TODO 这里可能会引起混淆,因为我们不会对 Target 实施 Scale 转换
|
||||
SetCurrentValue(MotionTransformProperty, RenderTransform);
|
||||
return base.ArrangeOverride(finalSize);
|
||||
}
|
||||
|
||||
// Determine the largest available size after the transformation
|
||||
Size finalSizeTransformed = ComputeLargestTransformedSize(finalSize);
|
||||
|
||||
if (IsSizeSmaller(finalSizeTransformed, MotionTransformRoot.DesiredSize))
|
||||
{
|
||||
// Some elements do not like being given less space than they asked for (ex: TextBlock)
|
||||
@ -181,9 +190,9 @@ public class MotionActorControl : Decorator
|
||||
{
|
||||
//// Unfortunately, all the work so far is invalid because the wrong DesiredSize was used
|
||||
//// Make a note of the actual DesiredSize
|
||||
//_childActualSize = arrangedsize;
|
||||
//// Force a new measure/arrange pass
|
||||
//InvalidateMeasure();
|
||||
// _childActualSize = arrangedsize;
|
||||
// //// Force a new measure/arrange pass
|
||||
// InvalidateMeasure();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -197,12 +206,12 @@ public class MotionActorControl : Decorator
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
if (MotionTransformRoot == null || MotionTransform == null)
|
||||
if (MotionTransformRoot == null || MotionTransform == null || UseRenderTransform)
|
||||
{
|
||||
return base.MeasureOverride(availableSize);
|
||||
}
|
||||
|
||||
Size measureSize;
|
||||
Size measureSize ;
|
||||
if (_childActualSize == default)
|
||||
{
|
||||
// Determine the largest size after the transformation
|
@ -2,14 +2,14 @@
|
||||
using Avalonia.Animation;
|
||||
using Avalonia.Media.Transformation;
|
||||
|
||||
namespace AtomUI.Controls.Utils;
|
||||
namespace AtomUI.MotionScene;
|
||||
|
||||
internal record MotionConfig
|
||||
internal record MotionConfigX
|
||||
{
|
||||
public RelativePoint RenderTransformOrigin { get; }
|
||||
public IList<Animation> Animations { get; }
|
||||
|
||||
public MotionConfig(RelativePoint renderTransformOrigin, IList<Animation> animations)
|
||||
public MotionConfigX(RelativePoint renderTransformOrigin, IList<Animation> animations)
|
||||
{
|
||||
RenderTransformOrigin = renderTransformOrigin;
|
||||
Animations = animations;
|
||||
@ -18,36 +18,36 @@ internal record MotionConfig
|
||||
|
||||
internal static partial class MotionFactory
|
||||
{
|
||||
static TransformOperations BuildScaleTransform(double scaleX, double scaleY)
|
||||
public static TransformOperations BuildScaleTransform(double scaleX, double scaleY)
|
||||
{
|
||||
var builder = new TransformOperations.Builder(1);
|
||||
builder.AppendScale(scaleX, scaleY);
|
||||
return builder.Build();
|
||||
}
|
||||
|
||||
static TransformOperations BuildScaleTransform(double scale)
|
||||
public static TransformOperations BuildScaleTransform(double scale)
|
||||
{
|
||||
return BuildScaleTransform(scale, scale);
|
||||
}
|
||||
|
||||
static TransformOperations BuildScaleXTransform(double scale)
|
||||
public static TransformOperations BuildScaleXTransform(double scale)
|
||||
{
|
||||
return BuildScaleTransform(scale, 1.0);
|
||||
}
|
||||
|
||||
static TransformOperations BuildScaleYTransform(double scale)
|
||||
public static TransformOperations BuildScaleYTransform(double scale)
|
||||
{
|
||||
return BuildScaleTransform(1.0, scale);
|
||||
}
|
||||
|
||||
static TransformOperations BuildTranslateTransform(double offsetX, double offsetY)
|
||||
public static TransformOperations BuildTranslateTransform(double offsetX, double offsetY)
|
||||
{
|
||||
var builder = new TransformOperations.Builder(1);
|
||||
builder.AppendTranslate(offsetX, offsetY);
|
||||
return builder.Build();
|
||||
}
|
||||
|
||||
static TransformOperations BuildTranslateScaleAndTransform(double scaleX, double scaleY, double offsetX, double offsetY)
|
||||
public static TransformOperations BuildTranslateScaleAndTransform(double scaleX, double scaleY, double offsetX, double offsetY)
|
||||
{
|
||||
var builder = new TransformOperations.Builder(2);
|
||||
builder.AppendScale(scaleX, scaleY);
|
@ -1,16 +1,16 @@
|
||||
using AtomUI.Controls.Primitives;
|
||||
using Avalonia;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace AtomUI.Controls.Utils;
|
||||
namespace AtomUI.MotionScene;
|
||||
|
||||
internal static class MotionInvoker
|
||||
{
|
||||
public static void Invoke(MotionActorControl target,
|
||||
MotionConfig motionConfig,
|
||||
MotionConfigX motionConfig,
|
||||
Action? aboutToStart = null,
|
||||
Action? completedAction = null)
|
||||
Action? completedAction = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
Dispatcher.UIThread.InvokeAsync(async () =>
|
||||
{
|
||||
@ -23,7 +23,7 @@ internal static class MotionInvoker
|
||||
|
||||
foreach (var animation in motionConfig.Animations)
|
||||
{
|
||||
await animation.RunAsync(target);
|
||||
await animation.RunAsync(target, cancellationToken);
|
||||
}
|
||||
|
||||
if (completedAction != null)
|
@ -2,7 +2,7 @@
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Media.Transformation;
|
||||
|
||||
namespace AtomUI.Controls.Utils;
|
||||
namespace AtomUI.MotionScene;
|
||||
|
||||
internal class MotionTransformOptionsAnimator : InterpolatingAnimator<TransformOperations>
|
||||
{
|
@ -1,15 +1,14 @@
|
||||
using AtomUI.Controls.Primitives;
|
||||
using Avalonia;
|
||||
using Avalonia;
|
||||
using Avalonia.Animation;
|
||||
using Avalonia.Animation.Easings;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Styling;
|
||||
|
||||
namespace AtomUI.Controls.Utils;
|
||||
namespace AtomUI.MotionScene;
|
||||
|
||||
internal static partial class MotionFactory
|
||||
{
|
||||
public static MotionConfig BuildMoveDownInMotion(double offset,
|
||||
public static MotionConfigX BuildMoveDownInMotion(double offset,
|
||||
TimeSpan duration,
|
||||
Easing? easing = null,
|
||||
FillMode fillMode = FillMode.None)
|
||||
@ -89,10 +88,10 @@ internal static partial class MotionFactory
|
||||
transformOrigin = new RelativePoint(0.0, 0.0, RelativeUnit.Relative);
|
||||
|
||||
animations.Add(animation);
|
||||
return new MotionConfig(transformOrigin, animations);
|
||||
return new MotionConfigX(transformOrigin, animations);
|
||||
}
|
||||
|
||||
public static MotionConfig BuildMoveDownOutMotion(double offset,
|
||||
public static MotionConfigX BuildMoveDownOutMotion(double offset,
|
||||
TimeSpan duration,
|
||||
Easing? easing = null,
|
||||
FillMode fillMode = FillMode.None)
|
||||
@ -173,10 +172,10 @@ internal static partial class MotionFactory
|
||||
transformOrigin = new RelativePoint(0, 0, RelativeUnit.Relative);
|
||||
|
||||
animations.Add(animation);
|
||||
return new MotionConfig(transformOrigin, animations);
|
||||
return new MotionConfigX(transformOrigin, animations);
|
||||
}
|
||||
|
||||
public static MotionConfig BuildMoveUpInMotion(double offset, TimeSpan duration, Easing? easing = null,
|
||||
public static MotionConfigX BuildMoveUpInMotion(double offset, TimeSpan duration, Easing? easing = null,
|
||||
FillMode fillMode = FillMode.None)
|
||||
{
|
||||
easing ??= new QuinticEaseOut();
|
||||
@ -254,10 +253,10 @@ internal static partial class MotionFactory
|
||||
transformOrigin = new RelativePoint(0.0, 0.0, RelativeUnit.Relative);
|
||||
|
||||
animations.Add(animation);
|
||||
return new MotionConfig(transformOrigin, animations);
|
||||
return new MotionConfigX(transformOrigin, animations);
|
||||
}
|
||||
|
||||
public static MotionConfig BuildMoveUpOutMotion(double offset, TimeSpan duration, Easing? easing = null,
|
||||
public static MotionConfigX BuildMoveUpOutMotion(double offset, TimeSpan duration, Easing? easing = null,
|
||||
FillMode fillMode = FillMode.None)
|
||||
{
|
||||
easing ??= new QuinticEaseIn();
|
||||
@ -345,10 +344,10 @@ internal static partial class MotionFactory
|
||||
transformOrigin = new RelativePoint(0, 0, RelativeUnit.Relative);
|
||||
|
||||
animations.Add(animation);
|
||||
return new MotionConfig(transformOrigin, animations);
|
||||
return new MotionConfigX(transformOrigin, animations);
|
||||
}
|
||||
|
||||
public static MotionConfig BuildMoveLeftInMotion(double offset, TimeSpan duration, Easing? easing = null,
|
||||
public static MotionConfigX BuildMoveLeftInMotion(double offset, TimeSpan duration, Easing? easing = null,
|
||||
FillMode fillMode = FillMode.None)
|
||||
{
|
||||
easing ??= new QuinticEaseOut();
|
||||
@ -429,10 +428,10 @@ internal static partial class MotionFactory
|
||||
transformOrigin = new RelativePoint(0.0, 0.0, RelativeUnit.Relative);
|
||||
|
||||
animations.Add(animation);
|
||||
return new MotionConfig(transformOrigin, animations);
|
||||
return new MotionConfigX(transformOrigin, animations);
|
||||
}
|
||||
|
||||
public static MotionConfig BuildMoveLeftOutMotion(double offset, TimeSpan duration, Easing? easing = null,
|
||||
public static MotionConfigX BuildMoveLeftOutMotion(double offset, TimeSpan duration, Easing? easing = null,
|
||||
FillMode fillMode = FillMode.None)
|
||||
{
|
||||
easing ??= new QuinticEaseIn();
|
||||
@ -509,10 +508,10 @@ internal static partial class MotionFactory
|
||||
transformOrigin = new RelativePoint(0, 0, RelativeUnit.Relative);
|
||||
|
||||
animations.Add(animation);
|
||||
return new MotionConfig(transformOrigin, animations);
|
||||
return new MotionConfigX(transformOrigin, animations);
|
||||
}
|
||||
|
||||
public static MotionConfig BuildMoveRightInMotion(double offset, TimeSpan duration, Easing? easing = null,
|
||||
public static MotionConfigX BuildMoveRightInMotion(double offset, TimeSpan duration, Easing? easing = null,
|
||||
FillMode fillMode = FillMode.None)
|
||||
{
|
||||
easing ??= new QuinticEaseOut();
|
||||
@ -590,10 +589,10 @@ internal static partial class MotionFactory
|
||||
transformOrigin = new RelativePoint(0.0, 0.0, RelativeUnit.Relative);
|
||||
|
||||
animations.Add(animation);
|
||||
return new MotionConfig(transformOrigin, animations);
|
||||
return new MotionConfigX(transformOrigin, animations);
|
||||
}
|
||||
|
||||
public static MotionConfig BuildMoveRightOutMotion(double offset, TimeSpan duration, Easing? easing = null,
|
||||
public static MotionConfigX BuildMoveRightOutMotion(double offset, TimeSpan duration, Easing? easing = null,
|
||||
FillMode fillMode = FillMode.None)
|
||||
{
|
||||
easing ??= new QuinticEaseIn();
|
||||
@ -671,6 +670,6 @@ internal static partial class MotionFactory
|
||||
transformOrigin = new RelativePoint(0, 0, RelativeUnit.Relative);
|
||||
|
||||
animations.Add(animation);
|
||||
return new MotionConfig(transformOrigin, animations);
|
||||
return new MotionConfigX(transformOrigin, animations);
|
||||
}
|
||||
}
|
@ -1,14 +1,13 @@
|
||||
using AtomUI.Controls.Primitives;
|
||||
using Avalonia;
|
||||
using Avalonia;
|
||||
using Avalonia.Animation;
|
||||
using Avalonia.Animation.Easings;
|
||||
using Avalonia.Styling;
|
||||
|
||||
namespace AtomUI.Controls.Utils;
|
||||
namespace AtomUI.MotionScene;
|
||||
|
||||
internal static partial class MotionFactory
|
||||
{
|
||||
public static MotionConfig BuildSlideUpInMotion(TimeSpan duration, Easing? easing = null,
|
||||
public static MotionConfigX BuildSlideUpInMotion(TimeSpan duration, Easing? easing = null,
|
||||
FillMode fillMode = FillMode.None)
|
||||
{
|
||||
easing ??= new CubicEaseOut();
|
||||
@ -63,10 +62,10 @@ internal static partial class MotionFactory
|
||||
transformOrigin = new RelativePoint(0.0, 0.0, RelativeUnit.Relative);
|
||||
|
||||
animations.Add(animation);
|
||||
return new MotionConfig(transformOrigin, animations);
|
||||
return new MotionConfigX(transformOrigin, animations);
|
||||
}
|
||||
|
||||
public static MotionConfig BuildSlideUpOutMotion(TimeSpan duration, Easing? easing = null,
|
||||
public static MotionConfigX BuildSlideUpOutMotion(TimeSpan duration, Easing? easing = null,
|
||||
FillMode fillMode = FillMode.None)
|
||||
{
|
||||
easing ??= new CubicEaseIn();
|
||||
@ -122,10 +121,10 @@ internal static partial class MotionFactory
|
||||
transformOrigin = new RelativePoint(0.0, 0.0, RelativeUnit.Relative);
|
||||
|
||||
animations.Add(animation);
|
||||
return new MotionConfig(transformOrigin, animations);
|
||||
return new MotionConfigX(transformOrigin, animations);
|
||||
}
|
||||
|
||||
public static MotionConfig BuildSlideDownInMotion(TimeSpan duration, Easing? easing = null,
|
||||
public static MotionConfigX BuildSlideDownInMotion(TimeSpan duration, Easing? easing = null,
|
||||
FillMode fillMode = FillMode.None)
|
||||
{
|
||||
easing ??= new CubicEaseOut();
|
||||
@ -181,10 +180,10 @@ internal static partial class MotionFactory
|
||||
transformOrigin = new RelativePoint(1.0, 1.0, RelativeUnit.Relative);
|
||||
|
||||
animations.Add(animation);
|
||||
return new MotionConfig(transformOrigin, animations);
|
||||
return new MotionConfigX(transformOrigin, animations);
|
||||
}
|
||||
|
||||
public static MotionConfig BuildSlideDownOutMotion(TimeSpan duration, Easing? easing = null,
|
||||
public static MotionConfigX BuildSlideDownOutMotion(TimeSpan duration, Easing? easing = null,
|
||||
FillMode fillMode = FillMode.None)
|
||||
{
|
||||
easing ??= new CubicEaseIn();
|
||||
@ -240,10 +239,10 @@ internal static partial class MotionFactory
|
||||
transformOrigin = new RelativePoint(1.0, 1.0, RelativeUnit.Relative);
|
||||
|
||||
animations.Add(animation);
|
||||
return new MotionConfig(transformOrigin, animations);
|
||||
return new MotionConfigX(transformOrigin, animations);
|
||||
}
|
||||
|
||||
public static MotionConfig BuildSlideLeftInMotion(TimeSpan duration, Easing? easing = null,
|
||||
public static MotionConfigX BuildSlideLeftInMotion(TimeSpan duration, Easing? easing = null,
|
||||
FillMode fillMode = FillMode.None)
|
||||
{
|
||||
easing ??= new CubicEaseOut();
|
||||
@ -299,10 +298,10 @@ internal static partial class MotionFactory
|
||||
transformOrigin = new RelativePoint(0.0, 0.0, RelativeUnit.Relative);
|
||||
|
||||
animations.Add(animation);
|
||||
return new MotionConfig(transformOrigin, animations);
|
||||
return new MotionConfigX(transformOrigin, animations);
|
||||
}
|
||||
|
||||
public static MotionConfig BuildSlideLeftOutMotion(TimeSpan duration, Easing? easing = null,
|
||||
public static MotionConfigX BuildSlideLeftOutMotion(TimeSpan duration, Easing? easing = null,
|
||||
FillMode fillMode = FillMode.None)
|
||||
{
|
||||
easing ??= new CubicEaseIn();
|
||||
@ -358,10 +357,10 @@ internal static partial class MotionFactory
|
||||
transformOrigin = new RelativePoint(0.0, 0.0, RelativeUnit.Relative);
|
||||
|
||||
animations.Add(animation);
|
||||
return new MotionConfig(transformOrigin, animations);
|
||||
return new MotionConfigX(transformOrigin, animations);
|
||||
}
|
||||
|
||||
public static MotionConfig BuildSlideRightInMotion(TimeSpan duration, Easing? easing = null,
|
||||
public static MotionConfigX BuildSlideRightInMotion(TimeSpan duration, Easing? easing = null,
|
||||
FillMode fillMode = FillMode.None)
|
||||
{
|
||||
easing ??= new CubicEaseOut();
|
||||
@ -417,10 +416,10 @@ internal static partial class MotionFactory
|
||||
transformOrigin = new RelativePoint(1.0, 0.0, RelativeUnit.Relative);
|
||||
|
||||
animations.Add(animation);
|
||||
return new MotionConfig(transformOrigin, animations);
|
||||
return new MotionConfigX(transformOrigin, animations);
|
||||
}
|
||||
|
||||
public static MotionConfig BuildSlideRightOutMotion(TimeSpan duration, Easing? easing = null,
|
||||
public static MotionConfigX BuildSlideRightOutMotion(TimeSpan duration, Easing? easing = null,
|
||||
FillMode fillMode = FillMode.None)
|
||||
{
|
||||
easing ??= new CubicEaseIn();
|
||||
@ -476,6 +475,6 @@ internal static partial class MotionFactory
|
||||
transformOrigin = new RelativePoint(1.0, 0.0, RelativeUnit.Relative);
|
||||
|
||||
animations.Add(animation);
|
||||
return new MotionConfig(transformOrigin, animations);
|
||||
return new MotionConfigX(transformOrigin, animations);
|
||||
}
|
||||
}
|
250
src/AtomUI.Controls/Badge/BadgeMotionFactory.cs
Normal file
250
src/AtomUI.Controls/Badge/BadgeMotionFactory.cs
Normal file
@ -0,0 +1,250 @@
|
||||
using AtomUI.MotionScene;
|
||||
using Avalonia;
|
||||
using Avalonia.Animation;
|
||||
using Avalonia.Animation.Easings;
|
||||
using Avalonia.Styling;
|
||||
|
||||
namespace AtomUI.Controls.Badge;
|
||||
|
||||
internal static class BadgeMotionFactory
|
||||
{
|
||||
public static MotionConfigX BuildBadgeZoomBadgeInMotion(TimeSpan duration, Easing? easing = null,
|
||||
FillMode fillMode = FillMode.None)
|
||||
{
|
||||
easing ??= new ExponentialEaseOut();
|
||||
var animations = new List<Animation>();
|
||||
RelativePoint transformOrigin = default;
|
||||
var animation = new Animation
|
||||
{
|
||||
Duration = duration,
|
||||
Easing = easing,
|
||||
FillMode = fillMode
|
||||
};
|
||||
|
||||
var startFrame = new KeyFrame
|
||||
{
|
||||
Cue = new Cue(0.0)
|
||||
};
|
||||
{
|
||||
var opacitySetter = new Setter
|
||||
{
|
||||
Property = Visual.OpacityProperty,
|
||||
Value = 0.0
|
||||
};
|
||||
startFrame.Setters.Add(opacitySetter);
|
||||
|
||||
var transformSetter = new Setter
|
||||
{
|
||||
Property = MotionActorControl.MotionTransformProperty,
|
||||
Value = MotionFactory.BuildScaleTransform(0.0)
|
||||
};
|
||||
startFrame.Setters.Add(transformSetter);
|
||||
}
|
||||
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);
|
||||
|
||||
var transformSetter = new Setter
|
||||
{
|
||||
Property = MotionActorControl.MotionTransformProperty,
|
||||
Value = MotionFactory.BuildScaleTransform(1.0)
|
||||
};
|
||||
endFrame.Setters.Add(transformSetter);
|
||||
}
|
||||
animation.Children.Add(endFrame);
|
||||
transformOrigin = new RelativePoint(0.5, 0.5, RelativeUnit.Relative);
|
||||
|
||||
animations.Add(animation);
|
||||
return new MotionConfigX(transformOrigin, animations);
|
||||
}
|
||||
|
||||
public static MotionConfigX BuildBadgeZoomBadgeOutMotion(TimeSpan duration, Easing? easing = null,
|
||||
FillMode fillMode = FillMode.None)
|
||||
{
|
||||
easing ??= new ExponentialEaseIn();
|
||||
var animations = new List<Animation>();
|
||||
RelativePoint transformOrigin = default;
|
||||
var animation = new Animation
|
||||
{
|
||||
Duration = duration,
|
||||
Easing = easing,
|
||||
FillMode = fillMode
|
||||
};
|
||||
|
||||
var startFrame = new KeyFrame
|
||||
{
|
||||
Cue = new Cue(0.0)
|
||||
};
|
||||
{
|
||||
var opacitySetter = new Setter
|
||||
{
|
||||
Property = Visual.OpacityProperty,
|
||||
Value = 1.0
|
||||
};
|
||||
startFrame.Setters.Add(opacitySetter);
|
||||
|
||||
var transformSetter = new Setter
|
||||
{
|
||||
Property = MotionActorControl.MotionTransformProperty,
|
||||
Value = MotionFactory.BuildScaleTransform(1.0)
|
||||
};
|
||||
startFrame.Setters.Add(transformSetter);
|
||||
}
|
||||
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);
|
||||
|
||||
var transformSetter = new Setter
|
||||
{
|
||||
Property = MotionActorControl.MotionTransformProperty,
|
||||
Value = MotionFactory.BuildScaleTransform(0.0)
|
||||
};
|
||||
endFrame.Setters.Add(transformSetter);
|
||||
}
|
||||
animation.Children.Add(endFrame);
|
||||
transformOrigin = new RelativePoint(0.5, 0.5, RelativeUnit.Relative);
|
||||
|
||||
animations.Add(animation);
|
||||
return new MotionConfigX(transformOrigin, animations);
|
||||
}
|
||||
|
||||
public static MotionConfigX BuildCountBadgeNoWrapperZoomBadgeInMotion(TimeSpan duration, Easing? easing = null,
|
||||
FillMode fillMode = FillMode.None)
|
||||
{
|
||||
easing ??= new CircularEaseOut();
|
||||
var animations = new List<Animation>();
|
||||
RelativePoint transformOrigin = default;
|
||||
var animation = new Animation
|
||||
{
|
||||
Duration = duration,
|
||||
Easing = easing,
|
||||
FillMode = fillMode
|
||||
};
|
||||
|
||||
var startFrame = new KeyFrame
|
||||
{
|
||||
Cue = new Cue(0.0)
|
||||
};
|
||||
{
|
||||
var opacitySetter = new Setter
|
||||
{
|
||||
Property = Visual.OpacityProperty,
|
||||
Value = 0.0
|
||||
};
|
||||
startFrame.Setters.Add(opacitySetter);
|
||||
|
||||
var transformSetter = new Setter
|
||||
{
|
||||
Property = MotionActorControl.MotionTransformProperty,
|
||||
Value = MotionFactory.BuildScaleTransform(0.0, 0.0)
|
||||
};
|
||||
startFrame.Setters.Add(transformSetter);
|
||||
}
|
||||
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);
|
||||
|
||||
var transformSetter = new Setter
|
||||
{
|
||||
Property = MotionActorControl.MotionTransformProperty,
|
||||
Value = MotionFactory.BuildScaleTransform(1.0, 1.0)
|
||||
};
|
||||
endFrame.Setters.Add(transformSetter);
|
||||
}
|
||||
animation.Children.Add(endFrame);
|
||||
transformOrigin = new RelativePoint(0.0, 0.0, RelativeUnit.Relative);
|
||||
|
||||
animations.Add(animation);
|
||||
return new MotionConfigX(transformOrigin, animations);
|
||||
}
|
||||
|
||||
public static MotionConfigX BuildCountBadgeNoWrapperZoomBadgeOutMotion(TimeSpan duration, Easing? easing = null,
|
||||
FillMode fillMode = FillMode.None)
|
||||
{
|
||||
easing ??= new CircularEaseIn();
|
||||
var animations = new List<Animation>();
|
||||
RelativePoint transformOrigin = default;
|
||||
var animation = new Animation
|
||||
{
|
||||
Duration = duration,
|
||||
Easing = easing,
|
||||
FillMode = fillMode
|
||||
};
|
||||
|
||||
var startFrame = new KeyFrame
|
||||
{
|
||||
Cue = new Cue(0.0)
|
||||
};
|
||||
{
|
||||
var opacitySetter = new Setter
|
||||
{
|
||||
Property = Visual.OpacityProperty,
|
||||
Value = 1.0
|
||||
};
|
||||
startFrame.Setters.Add(opacitySetter);
|
||||
|
||||
var transformSetter = new Setter
|
||||
{
|
||||
Property = MotionActorControl.MotionTransformProperty,
|
||||
Value = MotionFactory.BuildScaleTransform(1.0, 1.0)
|
||||
};
|
||||
startFrame.Setters.Add(transformSetter);
|
||||
}
|
||||
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);
|
||||
|
||||
var transformSetter = new Setter
|
||||
{
|
||||
Property = MotionActorControl.MotionTransformProperty,
|
||||
Value = MotionFactory.BuildScaleTransform(0.0, 0.0)
|
||||
};
|
||||
endFrame.Setters.Add(transformSetter);
|
||||
}
|
||||
animation.Children.Add(endFrame);
|
||||
transformOrigin = new RelativePoint(0.0, 0.0, RelativeUnit.Relative);
|
||||
|
||||
animations.Add(animation);
|
||||
return new MotionConfigX(transformOrigin, animations);
|
||||
}
|
||||
}
|
@ -62,6 +62,7 @@ internal class BadgeToken : AbstractControlDesignToken
|
||||
public Transform? BadgeRibbonCornerTransform { get; set; }
|
||||
public int BadgeRibbonCornerDarkenAmount { get; set; }
|
||||
public Thickness BadgeRibbonTextPadding { get; set; }
|
||||
public Thickness DotBadgeLabelMargin { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
@ -90,5 +91,6 @@ internal class BadgeToken : AbstractControlDesignToken
|
||||
BadgeRibbonCornerTransform = new ScaleTransform(1, 0.75);
|
||||
BadgeRibbonCornerDarkenAmount = 15;
|
||||
BadgeRibbonTextPadding = new Thickness(_globalToken.PaddingXS, 0);
|
||||
DotBadgeLabelMargin = new Thickness(_globalToken.MarginXS, 0, 0, 0);
|
||||
}
|
||||
}
|
@ -98,9 +98,7 @@ public class CountBadge : Control
|
||||
get => GetValue(BadgeIsVisibleProperty);
|
||||
set => SetValue(BadgeIsVisibleProperty, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region 内部属性定义
|
||||
|
13
src/AtomUI.Controls/Badge/CountBadgeAdornerTheme.cs
Normal file
13
src/AtomUI.Controls/Badge/CountBadgeAdornerTheme.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using AtomUI.Theme;
|
||||
using AtomUI.Theme.Styling;
|
||||
|
||||
namespace AtomUI.Controls.Badge;
|
||||
|
||||
[ControlThemeProvider]
|
||||
internal class CountBadgeAdornerTheme : BaseControlTheme
|
||||
{
|
||||
public CountBadgeAdornerTheme()
|
||||
: base(typeof(CountBadgeAdorner))
|
||||
{
|
||||
}
|
||||
}
|
@ -1,13 +1,9 @@
|
||||
using AtomUI.Controls.Badge;
|
||||
using AtomUI.Controls.MotionScene;
|
||||
using AtomUI.Data;
|
||||
using AtomUI.MotionScene;
|
||||
using AtomUI.Data;
|
||||
using AtomUI.Theme.Palette;
|
||||
using AtomUI.Theme.Styling;
|
||||
using AtomUI.Utils;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Metadata;
|
||||
|
||||
@ -83,38 +79,18 @@ public class DotBadge : Control
|
||||
get => GetValue(BadgeIsVisibleProperty);
|
||||
set => SetValue(BadgeIsVisibleProperty, value);
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region 内部属性一定
|
||||
|
||||
internal static readonly StyledProperty<TimeSpan> MotionDurationProperty =
|
||||
AvaloniaProperty.Register<CountBadge, TimeSpan>(
|
||||
nameof(MotionDuration));
|
||||
|
||||
internal TimeSpan MotionDuration
|
||||
{
|
||||
get => GetValue(MotionDurationProperty);
|
||||
set => SetValue(MotionDurationProperty, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private readonly bool _initialized = false;
|
||||
private DotBadgeAdorner? _dotBadgeAdorner;
|
||||
private AdornerLayer? _adornerLayer;
|
||||
private bool _animating;
|
||||
|
||||
|
||||
static DotBadge()
|
||||
{
|
||||
AffectsMeasure<DotBadge>(DecoratedTargetProperty, TextProperty);
|
||||
AffectsRender<DotBadge>(DotColorProperty, StatusProperty);
|
||||
}
|
||||
|
||||
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
||||
{
|
||||
base.OnAttachedToVisualTree(e);
|
||||
PrepareAdorner();
|
||||
HorizontalAlignmentProperty.OverrideDefaultValue<DotBadge>(HorizontalAlignment.Left);
|
||||
VerticalAlignmentProperty.OverrideDefaultValue<DotBadge>(VerticalAlignment.Top);
|
||||
}
|
||||
|
||||
private DotBadgeAdorner CreateDotBadgeAdorner()
|
||||
@ -135,7 +111,7 @@ public class DotBadge : Control
|
||||
|
||||
private void PrepareAdorner()
|
||||
{
|
||||
if (_adornerLayer is null && DecoratedTarget is not null)
|
||||
if (DecoratedTarget is not null)
|
||||
{
|
||||
var dotBadgeAdorner = CreateDotBadgeAdorner();
|
||||
_adornerLayer = AdornerLayer.GetAdornerLayer(this);
|
||||
@ -145,71 +121,18 @@ public class DotBadge : Control
|
||||
return;
|
||||
}
|
||||
|
||||
AdornerLayer.SetAdornedElement(dotBadgeAdorner, this);
|
||||
AdornerLayer.SetIsClipEnabled(dotBadgeAdorner, false);
|
||||
_adornerLayer.Children.Add(dotBadgeAdorner);
|
||||
dotBadgeAdorner.ApplyToTarget(_adornerLayer, this);
|
||||
}
|
||||
}
|
||||
|
||||
private void PrepareAdornerWithMotion()
|
||||
{
|
||||
PrepareAdorner();
|
||||
|
||||
if (VisualRoot is null || _animating)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_animating = true;
|
||||
var director = Director.Instance;
|
||||
var motion = new CountBadgeZoomBadgeIn();
|
||||
motion.ConfigureOpacity(MotionDuration);
|
||||
motion.ConfigureRenderTransform(MotionDuration);
|
||||
_dotBadgeAdorner!.AnimationRenderTransformOrigin = motion.MotionRenderTransformOrigin;
|
||||
var motionActor = new MotionActor(_dotBadgeAdorner, motion);
|
||||
motionActor.DispatchInSceneLayer = false;
|
||||
motionActor.Completed += (sender, args) =>
|
||||
{
|
||||
_dotBadgeAdorner.AnimationRenderTransformOrigin = null;
|
||||
_animating = false;
|
||||
};
|
||||
director?.Schedule(motionActor);
|
||||
}
|
||||
|
||||
|
||||
private void HideAdorner()
|
||||
{
|
||||
// 这里需要抛出异常吗?
|
||||
if (_adornerLayer is null || _dotBadgeAdorner is null)
|
||||
if ( _dotBadgeAdorner is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_adornerLayer.Children.Remove(_dotBadgeAdorner);
|
||||
_adornerLayer = null;
|
||||
}
|
||||
|
||||
private void HideAdornerWithMotion()
|
||||
{
|
||||
if (VisualRoot is null || _animating)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_animating = true;
|
||||
var director = Director.Instance;
|
||||
var motion = new CountBadgeZoomBadgeOut();
|
||||
motion.ConfigureOpacity(MotionDuration);
|
||||
motion.ConfigureRenderTransform(MotionDuration);
|
||||
_dotBadgeAdorner!.AnimationRenderTransformOrigin = motion.MotionRenderTransformOrigin;
|
||||
var motionActor = new MotionActor(_dotBadgeAdorner, motion);
|
||||
motionActor.DispatchInSceneLayer = false;
|
||||
motionActor.Completed += (sender, args) =>
|
||||
{
|
||||
HideAdorner();
|
||||
_dotBadgeAdorner.AnimationRenderTransformOrigin = null;
|
||||
_animating = false;
|
||||
};
|
||||
director?.Schedule(motionActor);
|
||||
_dotBadgeAdorner.DetachFromTarget(_adornerLayer);
|
||||
}
|
||||
|
||||
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
|
||||
@ -217,7 +140,7 @@ public class DotBadge : Control
|
||||
base.OnDetachedFromVisualTree(e);
|
||||
HideAdorner();
|
||||
}
|
||||
|
||||
|
||||
private void SetupTokenBindings()
|
||||
{
|
||||
if (_dotBadgeAdorner is not null)
|
||||
@ -226,8 +149,6 @@ public class DotBadge : Control
|
||||
BindUtils.RelayBind(this, TextProperty, _dotBadgeAdorner, DotBadgeAdorner.TextProperty);
|
||||
BindUtils.RelayBind(this, OffsetProperty, _dotBadgeAdorner, DotBadgeAdorner.OffsetProperty);
|
||||
}
|
||||
|
||||
TokenResourceBinder.CreateTokenBinding(this, MotionDurationProperty, GlobalTokenResourceKey.MotionDurationSlow);
|
||||
}
|
||||
|
||||
private void HandleDecoratedTargetChanged()
|
||||
@ -240,7 +161,7 @@ public class DotBadge : Control
|
||||
((ISetLogicalParent)_dotBadgeAdorner).SetParent(this);
|
||||
VisualChildren.Add(_dotBadgeAdorner);
|
||||
}
|
||||
else if (DecoratedTarget is not null)
|
||||
else
|
||||
{
|
||||
_dotBadgeAdorner.IsAdornerMode = true;
|
||||
VisualChildren.Add(DecoratedTarget);
|
||||
@ -256,6 +177,10 @@ public class DotBadge : Control
|
||||
{
|
||||
CreateDotBadgeAdorner();
|
||||
}
|
||||
else
|
||||
{
|
||||
PrepareAdorner();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs e)
|
||||
@ -280,37 +205,17 @@ public class DotBadge : Control
|
||||
}
|
||||
else if (e.Property == BadgeIsVisibleProperty)
|
||||
{
|
||||
var badgeIsVisible = e.GetNewValue<bool>();
|
||||
if (badgeIsVisible)
|
||||
if (BadgeIsVisible)
|
||||
{
|
||||
if (_adornerLayer is not null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (DecoratedTarget is not null)
|
||||
{
|
||||
PrepareAdornerWithMotion();
|
||||
}
|
||||
else
|
||||
{
|
||||
PrepareAdorner();
|
||||
}
|
||||
PrepareAdorner();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (DecoratedTarget is not null)
|
||||
{
|
||||
HideAdornerWithMotion();
|
||||
}
|
||||
else
|
||||
{
|
||||
HideAdorner();
|
||||
}
|
||||
HideAdorner();
|
||||
}
|
||||
}
|
||||
|
||||
if (_initialized)
|
||||
if (VisualRoot is not null)
|
||||
{
|
||||
if (e.Property == DecoratedTargetProperty)
|
||||
{
|
||||
@ -342,4 +247,5 @@ public class DotBadge : Control
|
||||
_dotBadgeAdorner!.BadgeDotColor = new SolidColorBrush(color);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,20 +1,32 @@
|
||||
using AtomUI.Theme.Styling;
|
||||
using AtomUI.Controls.Badge;
|
||||
using AtomUI.MotionScene;
|
||||
using AtomUI.Theme.Styling;
|
||||
using AtomUI.Utils;
|
||||
using Avalonia;
|
||||
using Avalonia.Animation;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.LogicalTree;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Styling;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
internal class DotBadgeAdorner : Control
|
||||
internal class DotBadgeAdorner : TemplatedControl
|
||||
{
|
||||
public static readonly StyledProperty<IBrush?> BadgeDotColorProperty =
|
||||
AvaloniaProperty.Register<DotBadgeAdorner, IBrush?>(
|
||||
nameof(BadgeDotColor));
|
||||
|
||||
public static readonly DirectProperty<DotBadgeAdorner, DotBadgeStatus?> StatusProperty =
|
||||
AvaloniaProperty.RegisterDirect<DotBadgeAdorner, DotBadgeStatus?>(
|
||||
nameof(Status),
|
||||
o => o.Status,
|
||||
(o, v) => o.Status = v);
|
||||
|
||||
internal IBrush? BadgeDotColor
|
||||
{
|
||||
get => GetValue(BadgeDotColorProperty);
|
||||
set => SetValue(BadgeDotColorProperty, value);
|
||||
}
|
||||
|
||||
private DotBadgeStatus? _status;
|
||||
|
||||
@ -44,30 +56,6 @@ internal class DotBadgeAdorner : Control
|
||||
o => o.IsAdornerMode,
|
||||
(o, v) => o.IsAdornerMode = v);
|
||||
|
||||
internal static readonly StyledProperty<IBrush?> BadgeDotColorProperty =
|
||||
AvaloniaProperty.Register<DotBadgeAdorner, IBrush?>(
|
||||
nameof(BadgeDotColor));
|
||||
|
||||
internal static readonly StyledProperty<double> DotSizeProperty =
|
||||
AvaloniaProperty.Register<DotBadgeAdorner, double>(
|
||||
nameof(DotSize));
|
||||
|
||||
internal static readonly StyledProperty<double> StatusSizeProperty =
|
||||
AvaloniaProperty.Register<DotBadgeAdorner, double>(
|
||||
nameof(StatusSize));
|
||||
|
||||
internal static readonly StyledProperty<IBrush?> BadgeShadowColorProperty =
|
||||
AvaloniaProperty.Register<DotBadgeAdorner, IBrush?>(
|
||||
nameof(BadgeShadowColor));
|
||||
|
||||
private static readonly StyledProperty<double> BadgeShadowSizeProperty =
|
||||
AvaloniaProperty.Register<DotBadgeAdorner, double>(
|
||||
nameof(BadgeShadowSize));
|
||||
|
||||
private static readonly StyledProperty<double> BadgeTextMarginInlineProperty =
|
||||
AvaloniaProperty.Register<DotBadgeAdorner, double>(
|
||||
nameof(BadgeTextMarginInline));
|
||||
|
||||
public static readonly StyledProperty<Point> OffsetProperty =
|
||||
AvaloniaProperty.Register<DotBadgeAdorner, Point>(
|
||||
nameof(Offset));
|
||||
@ -85,256 +73,151 @@ internal class DotBadgeAdorner : Control
|
||||
get => GetValue(OffsetProperty);
|
||||
set => SetValue(OffsetProperty, value);
|
||||
}
|
||||
|
||||
#region 内部属性定义
|
||||
|
||||
public double DotSize
|
||||
internal static readonly StyledProperty<TimeSpan> MotionDurationProperty =
|
||||
AvaloniaProperty.Register<DotBadgeAdorner, TimeSpan>(
|
||||
nameof(MotionDuration));
|
||||
|
||||
internal TimeSpan MotionDuration
|
||||
{
|
||||
get => GetValue(DotSizeProperty);
|
||||
set => SetValue(DotSizeProperty, value);
|
||||
get => GetValue(MotionDurationProperty);
|
||||
set => SetValue(MotionDurationProperty, value);
|
||||
}
|
||||
|
||||
public double StatusSize
|
||||
{
|
||||
get => GetValue(StatusSizeProperty);
|
||||
set => SetValue(StatusSizeProperty, value);
|
||||
}
|
||||
|
||||
internal IBrush? BadgeDotColor
|
||||
{
|
||||
get => GetValue(BadgeDotColorProperty);
|
||||
set => SetValue(BadgeDotColorProperty, value);
|
||||
}
|
||||
|
||||
internal IBrush? BadgeShadowColor
|
||||
{
|
||||
get => GetValue(BadgeShadowColorProperty);
|
||||
set => SetValue(BadgeShadowColorProperty, value);
|
||||
}
|
||||
|
||||
public double BadgeShadowSize
|
||||
{
|
||||
get => GetValue(BadgeShadowSizeProperty);
|
||||
set => SetValue(BadgeShadowSizeProperty, value);
|
||||
}
|
||||
|
||||
public double BadgeTextMarginInline
|
||||
{
|
||||
get => GetValue(BadgeTextMarginInlineProperty);
|
||||
set => SetValue(BadgeTextMarginInlineProperty, value);
|
||||
}
|
||||
|
||||
private bool _initialized;
|
||||
private Label? _textLabel;
|
||||
|
||||
private BoxShadows _boxShadows;
|
||||
|
||||
// 不知道为什么这个值会被 AdornerLayer 重写
|
||||
// 非常不优美,但是能工作
|
||||
internal RelativePoint? AnimationRenderTransformOrigin;
|
||||
|
||||
#endregion
|
||||
|
||||
private MotionActorControl? _indicatorMotionActor;
|
||||
private CancellationTokenSource? _motionCancellationTokenSource;
|
||||
|
||||
static DotBadgeAdorner()
|
||||
{
|
||||
AffectsMeasure<DotBadge>(TextProperty, IsAdornerModeProperty);
|
||||
AffectsRender<DotBadge>(BadgeDotColorProperty, OffsetProperty);
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
base.OnApplyTemplate(e);
|
||||
TokenResourceBinder.CreateTokenBinding(this, MotionDurationProperty, GlobalTokenResourceKey.MotionDurationMid);
|
||||
SetupBadgeColor();
|
||||
_indicatorMotionActor = e.NameScope.Get<MotionActorControl>(DotBadgeAdornerTheme.IndicatorMotionActorPart);
|
||||
}
|
||||
|
||||
private void ApplyShowMotion()
|
||||
{
|
||||
if (_indicatorMotionActor is not null)
|
||||
{
|
||||
_indicatorMotionActor.IsVisible = false;
|
||||
var zoomBadgeInMotionConfig = BadgeMotionFactory.BuildBadgeZoomBadgeInMotion(MotionDuration, null,
|
||||
FillMode.Forward);
|
||||
MotionInvoker.Invoke(_indicatorMotionActor, zoomBadgeInMotionConfig, () =>
|
||||
{
|
||||
_indicatorMotionActor.IsVisible = true;
|
||||
}, null, _motionCancellationTokenSource!.Token);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed override void ApplyTemplate()
|
||||
private void ApplyHideMotion(Action completedAction)
|
||||
{
|
||||
base.ApplyTemplate();
|
||||
if (!_initialized)
|
||||
if (_indicatorMotionActor is not null)
|
||||
{
|
||||
_textLabel = new Label
|
||||
var zoomBadgeOutMotionConfig = BadgeMotionFactory.BuildBadgeZoomBadgeOutMotion(MotionDuration, null,
|
||||
FillMode.Forward);
|
||||
_motionCancellationTokenSource?.Cancel();
|
||||
_motionCancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
MotionInvoker.Invoke(_indicatorMotionActor, zoomBadgeOutMotionConfig, null, () =>
|
||||
{
|
||||
Content = Text,
|
||||
HorizontalAlignment = HorizontalAlignment.Left,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
HorizontalContentAlignment = HorizontalAlignment.Center,
|
||||
VerticalContentAlignment = VerticalAlignment.Center,
|
||||
Padding = new Thickness(0)
|
||||
};
|
||||
|
||||
((ISetLogicalParent)_textLabel).SetParent(this);
|
||||
VisualChildren.Add(_textLabel);
|
||||
BuildBoxShadow();
|
||||
_initialized = true;
|
||||
completedAction();
|
||||
}, _motionCancellationTokenSource.Token);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
|
||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
||||
{
|
||||
base.OnAttachedToLogicalTree(e);
|
||||
BuildStyles();
|
||||
}
|
||||
|
||||
private void BuildStyles()
|
||||
{
|
||||
if (Styles.Count == 0)
|
||||
base.OnPropertyChanged(change);
|
||||
if (VisualRoot is not null)
|
||||
{
|
||||
BuildBadgeColorStyle();
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildBadgeColorStyle()
|
||||
{
|
||||
var commonStyle = new Style(selector => selector.OfType<DotBadgeAdorner>());
|
||||
commonStyle.Add(BadgeTextMarginInlineProperty, GlobalTokenResourceKey.MarginXS);
|
||||
commonStyle.Add(BadgeDotColorProperty, BadgeTokenResourceKey.BadgeColor);
|
||||
commonStyle.Add(DotSizeProperty, BadgeTokenResourceKey.DotSize);
|
||||
commonStyle.Add(StatusSizeProperty, BadgeTokenResourceKey.StatusSize);
|
||||
commonStyle.Add(BadgeShadowSizeProperty, BadgeTokenResourceKey.BadgeShadowSize);
|
||||
commonStyle.Add(BadgeShadowColorProperty, BadgeTokenResourceKey.BadgeShadowColor);
|
||||
|
||||
var errorStatusStyle =
|
||||
new Style(selector => selector.Nesting().PropertyEquals(StatusProperty, DotBadgeStatus.Error));
|
||||
errorStatusStyle.Add(BadgeDotColorProperty, GlobalTokenResourceKey.ColorError);
|
||||
commonStyle.Add(errorStatusStyle);
|
||||
|
||||
var successStatusStyle =
|
||||
new Style(selector => selector.Nesting().PropertyEquals(StatusProperty, DotBadgeStatus.Success));
|
||||
successStatusStyle.Add(BadgeDotColorProperty, GlobalTokenResourceKey.ColorSuccess);
|
||||
commonStyle.Add(successStatusStyle);
|
||||
|
||||
var warningStatusStyle =
|
||||
new Style(selector => selector.Nesting().PropertyEquals(StatusProperty, DotBadgeStatus.Warning));
|
||||
warningStatusStyle.Add(BadgeDotColorProperty, GlobalTokenResourceKey.ColorWarning);
|
||||
commonStyle.Add(warningStatusStyle);
|
||||
|
||||
var defaultStatusStyle =
|
||||
new Style(selector => selector.Nesting().PropertyEquals(StatusProperty, DotBadgeStatus.Default));
|
||||
defaultStatusStyle.Add(BadgeDotColorProperty, GlobalTokenResourceKey.ColorTextPlaceholder);
|
||||
commonStyle.Add(defaultStatusStyle);
|
||||
|
||||
var processingStatusStyle = new Style(selector =>
|
||||
selector.Nesting().PropertyEquals(StatusProperty, DotBadgeStatus.Processing));
|
||||
processingStatusStyle.Add(BadgeDotColorProperty, GlobalTokenResourceKey.ColorInfo);
|
||||
commonStyle.Add(processingStatusStyle);
|
||||
|
||||
Styles.Add(commonStyle);
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
var targetWidth = 0d;
|
||||
var targetHeight = 0d;
|
||||
if (IsAdornerMode)
|
||||
{
|
||||
targetWidth = availableSize.Width;
|
||||
targetHeight = availableSize.Height;
|
||||
}
|
||||
else
|
||||
{
|
||||
var textSize = base.MeasureOverride(availableSize);
|
||||
targetWidth += StatusSize;
|
||||
targetWidth += textSize.Width;
|
||||
targetHeight += Math.Max(textSize.Height, StatusSize);
|
||||
if (textSize.Width > 0)
|
||||
if (change.Property == StatusProperty)
|
||||
{
|
||||
targetWidth += BadgeTextMarginInline;
|
||||
SetupBadgeColor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupBadgeColor()
|
||||
{
|
||||
if (Status is not null)
|
||||
{
|
||||
if (Status == DotBadgeStatus.Error)
|
||||
{
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(this, BadgeDotColorProperty,
|
||||
GlobalTokenResourceKey.ColorError);
|
||||
}
|
||||
else if (Status == DotBadgeStatus.Success)
|
||||
{
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(this, BadgeDotColorProperty,
|
||||
GlobalTokenResourceKey.ColorSuccess);
|
||||
}
|
||||
else if (Status == DotBadgeStatus.Warning)
|
||||
{
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(this, BadgeDotColorProperty,
|
||||
GlobalTokenResourceKey.ColorWarning);
|
||||
}
|
||||
else if (Status == DotBadgeStatus.Processing)
|
||||
{
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(this, BadgeDotColorProperty,
|
||||
GlobalTokenResourceKey.ColorInfo);
|
||||
}
|
||||
else if (Status == DotBadgeStatus.Default)
|
||||
{
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(this, BadgeDotColorProperty,
|
||||
GlobalTokenResourceKey.ColorTextPlaceholder);
|
||||
}
|
||||
}
|
||||
|
||||
return new Size(targetWidth, targetHeight);
|
||||
}
|
||||
|
||||
protected override Size ArrangeOverride(Size finalSize)
|
||||
{
|
||||
if (!IsAdornerMode)
|
||||
var size = base.ArrangeOverride(finalSize);
|
||||
if (IsAdornerMode && _indicatorMotionActor is not null)
|
||||
{
|
||||
double textOffsetX = 0;
|
||||
if (IsAdornerMode)
|
||||
{
|
||||
textOffsetX += DotSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
textOffsetX += StatusSize;
|
||||
}
|
||||
|
||||
textOffsetX += BadgeTextMarginInline;
|
||||
var textRect = new Rect(new Point(textOffsetX, 0), _textLabel!.DesiredSize);
|
||||
_textLabel.Arrange(textRect);
|
||||
var offsetX = Offset.X;
|
||||
var offsetY = Offset.Y;
|
||||
var dotSize = _indicatorMotionActor.Bounds.Size;
|
||||
offsetX += dotSize.Width / 3;
|
||||
offsetY += dotSize.Height / 3;
|
||||
_indicatorMotionActor.Arrange(new Rect(new Point(offsetX, -offsetY), dotSize));
|
||||
}
|
||||
|
||||
return finalSize;
|
||||
return size;
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs e)
|
||||
internal void ApplyToTarget(AdornerLayer? adornerLayer, Control adorned)
|
||||
{
|
||||
base.OnPropertyChanged(e);
|
||||
if (e.Property == IsAdornerModeProperty)
|
||||
if (adornerLayer is null)
|
||||
{
|
||||
var newValue = e.GetNewValue<bool>();
|
||||
if (_textLabel is not null)
|
||||
{
|
||||
_textLabel.IsVisible = !newValue;
|
||||
}
|
||||
}
|
||||
else if (e.Property == BadgeShadowSizeProperty ||
|
||||
e.Property == BadgeShadowColorProperty)
|
||||
{
|
||||
BuildBoxShadow();
|
||||
return;
|
||||
}
|
||||
|
||||
adornerLayer.Children.Remove(this);
|
||||
|
||||
AdornerLayer.SetAdornedElement(this, adorned);
|
||||
AdornerLayer.SetIsClipEnabled(this, false);
|
||||
adornerLayer.Children.Add(this);
|
||||
|
||||
_motionCancellationTokenSource?.Cancel();
|
||||
_motionCancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
ApplyShowMotion();
|
||||
}
|
||||
|
||||
public override void Render(DrawingContext context)
|
||||
internal void DetachFromTarget(AdornerLayer? adornerLayer)
|
||||
{
|
||||
var dotSize = 0d;
|
||||
if (IsAdornerMode)
|
||||
if (adornerLayer is null)
|
||||
{
|
||||
dotSize = DotSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
dotSize = StatusSize;
|
||||
}
|
||||
|
||||
var offsetX = 0d;
|
||||
var offsetY = 0d;
|
||||
if (IsAdornerMode)
|
||||
{
|
||||
offsetX = DesiredSize.Width - dotSize / 2;
|
||||
offsetY = -dotSize / 2;
|
||||
offsetX -= Offset.X;
|
||||
offsetY += Offset.Y;
|
||||
}
|
||||
else
|
||||
{
|
||||
offsetY = (DesiredSize.Height - dotSize) / 2;
|
||||
}
|
||||
|
||||
var dotRect = new Rect(new Point(offsetX, offsetY), new Size(dotSize, dotSize));
|
||||
|
||||
if (RenderTransform is not null)
|
||||
{
|
||||
Point origin;
|
||||
if (AnimationRenderTransformOrigin.HasValue)
|
||||
{
|
||||
origin = AnimationRenderTransformOrigin.Value.ToPixels(dotRect.Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
origin = RenderTransformOrigin.ToPixels(dotRect.Size);
|
||||
}
|
||||
|
||||
var offset = Matrix.CreateTranslation(new Point(origin.X + offsetX, origin.Y + offsetY));
|
||||
var renderTransform = -offset * RenderTransform.Value * offset;
|
||||
context.PushTransform(renderTransform);
|
||||
}
|
||||
|
||||
context.DrawRectangle(BadgeDotColor, null, dotRect, dotSize, dotSize, _boxShadows);
|
||||
}
|
||||
|
||||
private void BuildBoxShadow()
|
||||
{
|
||||
if (BadgeShadowColor is not null)
|
||||
{
|
||||
_boxShadows = new BoxShadows(new BoxShadow
|
||||
{
|
||||
OffsetX = 0,
|
||||
OffsetY = 0,
|
||||
Blur = 0,
|
||||
Spread = BadgeShadowSize,
|
||||
Color = ((SolidColorBrush)BadgeShadowColor).Color
|
||||
});
|
||||
return;
|
||||
}
|
||||
ApplyHideMotion(() => adornerLayer.Children.Remove(this));
|
||||
}
|
||||
}
|
105
src/AtomUI.Controls/Badge/DotBadgeAdornerTheme.cs
Normal file
105
src/AtomUI.Controls/Badge/DotBadgeAdornerTheme.cs
Normal file
@ -0,0 +1,105 @@
|
||||
using AtomUI.MotionScene;
|
||||
using AtomUI.Theme;
|
||||
using AtomUI.Theme.Styling;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Avalonia.Data;
|
||||
using Avalonia.Data.Converters;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Styling;
|
||||
|
||||
namespace AtomUI.Controls.Badge;
|
||||
|
||||
[ControlThemeProvider]
|
||||
internal class DotBadgeAdornerTheme : BaseControlTheme
|
||||
{
|
||||
internal const string IndicatorMotionActorPart = "PART_IndicatorMotionActor";
|
||||
internal const string IndicatorPart = "PART_Indicator";
|
||||
internal const string LabelPart = "PART_Label";
|
||||
internal const string RootLayoutPart = "PART_RootLayout";
|
||||
|
||||
public DotBadgeAdornerTheme()
|
||||
: base(typeof(DotBadgeAdorner))
|
||||
{
|
||||
}
|
||||
|
||||
protected override IControlTemplate? BuildControlTemplate()
|
||||
{
|
||||
return new FuncControlTemplate<DotBadgeAdorner>((adorner, scope) =>
|
||||
{
|
||||
var layout = new DockPanel()
|
||||
{
|
||||
Name = RootLayoutPart,
|
||||
LastChildFill = true,
|
||||
ClipToBounds = false
|
||||
};
|
||||
BuildIndicator(layout, scope);
|
||||
BuildLabel(layout, scope);
|
||||
return layout;
|
||||
});
|
||||
}
|
||||
|
||||
private void BuildIndicator(DockPanel layout, INameScope scope)
|
||||
{
|
||||
var indicatorMotionActor = new MotionActorControl()
|
||||
{
|
||||
Name = IndicatorMotionActorPart,
|
||||
ClipToBounds = false,
|
||||
UseRenderTransform = true
|
||||
};
|
||||
indicatorMotionActor.RegisterInNameScope(scope);
|
||||
var indicator = new DotBadgeIndicator()
|
||||
{
|
||||
Name = IndicatorPart
|
||||
};
|
||||
indicator.RegisterInNameScope(scope);
|
||||
DockPanel.SetDock(indicatorMotionActor, Dock.Left);
|
||||
|
||||
CreateTemplateParentBinding(indicator, DotBadgeIndicator.BadgeDotColorProperty, DotBadgeAdorner.BadgeDotColorProperty);
|
||||
indicatorMotionActor.Child = indicator;
|
||||
layout.Children.Add(indicatorMotionActor);
|
||||
}
|
||||
|
||||
private void BuildLabel(DockPanel layout, INameScope scope)
|
||||
{
|
||||
var label = new Label()
|
||||
{
|
||||
Name = LabelPart
|
||||
};
|
||||
label.RegisterInNameScope(scope);
|
||||
CreateTemplateParentBinding(label, Label.ContentProperty, DotBadgeAdorner.TextProperty);
|
||||
CreateTemplateParentBinding(label, Label.IsVisibleProperty, DotBadgeAdorner.IsAdornerModeProperty,
|
||||
BindingMode.Default,
|
||||
BoolConverters.Not);
|
||||
layout.Children.Add(label);
|
||||
}
|
||||
|
||||
protected override void BuildStyles()
|
||||
{
|
||||
var commonStyle = new Style(selector => selector.Nesting());
|
||||
commonStyle.Add(DotBadgeAdorner.ClipToBoundsProperty, false);
|
||||
commonStyle.Add(DotBadgeAdorner.BadgeDotColorProperty, BadgeTokenResourceKey.BadgeColor);
|
||||
var inAdornerStyle = new Style(selector => selector.Nesting().PropertyEquals(DotBadgeAdorner.IsAdornerModeProperty, true));
|
||||
var layoutStyle = new Style(selector => selector.Nesting().Template().Name(RootLayoutPart));
|
||||
layoutStyle.Add(DockPanel.HorizontalAlignmentProperty, HorizontalAlignment.Right);
|
||||
layoutStyle.Add(DockPanel.VerticalAlignmentProperty, VerticalAlignment.Top);
|
||||
inAdornerStyle.Add(layoutStyle);
|
||||
commonStyle.Add(inAdornerStyle);
|
||||
|
||||
var labelStyle = new Style(selector => selector.Nesting().Template().Name(LabelPart));
|
||||
labelStyle.Add(Label.HorizontalAlignmentProperty, HorizontalAlignment.Left);
|
||||
labelStyle.Add(Label.VerticalAlignmentProperty, VerticalAlignment.Center);
|
||||
labelStyle.Add(Label.HorizontalContentAlignmentProperty, HorizontalAlignment.Center);
|
||||
labelStyle.Add(Label.VerticalContentAlignmentProperty, VerticalAlignment.Center);
|
||||
labelStyle.Add(Label.MarginProperty, BadgeTokenResourceKey.DotBadgeLabelMargin);
|
||||
commonStyle.Add(labelStyle);
|
||||
|
||||
var indicatorStyle = new Style(selector => selector.Nesting().Template().Name(IndicatorMotionActorPart));
|
||||
|
||||
indicatorStyle.Add(MotionActorControl.WidthProperty, BadgeTokenResourceKey.DotSize);
|
||||
indicatorStyle.Add(MotionActorControl.HeightProperty, BadgeTokenResourceKey.DotSize);
|
||||
commonStyle.Add(indicatorStyle);
|
||||
|
||||
Add(commonStyle);
|
||||
}
|
||||
}
|
90
src/AtomUI.Controls/Badge/DotBadgeIndicator.cs
Normal file
90
src/AtomUI.Controls/Badge/DotBadgeIndicator.cs
Normal file
@ -0,0 +1,90 @@
|
||||
using AtomUI.Theme.Styling;
|
||||
using AtomUI.Utils;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Media;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
internal class DotBadgeIndicator : Control
|
||||
{
|
||||
internal static readonly StyledProperty<IBrush?> BadgeDotColorProperty =
|
||||
AvaloniaProperty.Register<DotBadgeIndicator, IBrush?>(
|
||||
nameof(BadgeDotColor));
|
||||
|
||||
internal static readonly StyledProperty<IBrush?> BadgeShadowColorProperty =
|
||||
AvaloniaProperty.Register<DotBadgeIndicator, IBrush?>(
|
||||
nameof(BadgeShadowColor));
|
||||
|
||||
internal static readonly StyledProperty<double> BadgeShadowSizeProperty =
|
||||
AvaloniaProperty.Register<DotBadgeIndicator, double>(
|
||||
nameof(BadgeShadowSize));
|
||||
|
||||
internal IBrush? BadgeDotColor
|
||||
{
|
||||
get => GetValue(BadgeDotColorProperty);
|
||||
set => SetValue(BadgeDotColorProperty, value);
|
||||
}
|
||||
|
||||
internal IBrush? BadgeShadowColor
|
||||
{
|
||||
get => GetValue(BadgeShadowColorProperty);
|
||||
set => SetValue(BadgeShadowColorProperty, value);
|
||||
}
|
||||
|
||||
public double BadgeShadowSize
|
||||
{
|
||||
get => GetValue(BadgeShadowSizeProperty);
|
||||
set => SetValue(BadgeShadowSizeProperty, value);
|
||||
}
|
||||
|
||||
private BoxShadows _boxShadows;
|
||||
|
||||
static DotBadgeIndicator()
|
||||
{
|
||||
AffectsRender<DotBadgeIndicator>(BadgeDotColorProperty, BadgeShadowSizeProperty);
|
||||
}
|
||||
|
||||
public sealed override void ApplyTemplate()
|
||||
{
|
||||
base.ApplyTemplate();
|
||||
BuildBoxShadow();
|
||||
|
||||
TokenResourceBinder.CreateTokenBinding(this, BadgeShadowSizeProperty, BadgeTokenResourceKey.BadgeShadowSize);
|
||||
TokenResourceBinder.CreateTokenBinding(this, BadgeShadowColorProperty, BadgeTokenResourceKey.BadgeShadowColor);
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnPropertyChanged(e);
|
||||
if (e.Property == BadgeShadowSizeProperty ||
|
||||
e.Property == BadgeShadowColorProperty)
|
||||
{
|
||||
BuildBoxShadow(true);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Render(DrawingContext context)
|
||||
{
|
||||
context.DrawRectangle(BadgeDotColor, null, new Rect(Bounds.Size), Bounds.Width / 2, Bounds.Height / 2,
|
||||
_boxShadows);
|
||||
}
|
||||
|
||||
private void BuildBoxShadow(bool force = false)
|
||||
{
|
||||
if (_boxShadows == default || force)
|
||||
{
|
||||
if (BadgeShadowColor is not null)
|
||||
{
|
||||
_boxShadows = new BoxShadows(new BoxShadow
|
||||
{
|
||||
OffsetX = 0,
|
||||
OffsetY = 0,
|
||||
Blur = 0,
|
||||
Spread = BadgeShadowSize,
|
||||
Color = ((SolidColorBrush)BadgeShadowColor).Color
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
using AtomUI.Controls.Primitives;
|
||||
using AtomUI.Controls.Utils;
|
||||
using AtomUI.Controls.Utils;
|
||||
using AtomUI.MotionScene;
|
||||
using AtomUI.Theme.Styling;
|
||||
using AtomUI.Utils;
|
||||
using Avalonia;
|
||||
|
@ -1,5 +1,5 @@
|
||||
using AtomUI.Controls.Primitives;
|
||||
using AtomUI.Controls.Utils;
|
||||
using AtomUI.Controls.Utils;
|
||||
using AtomUI.MotionScene;
|
||||
using AtomUI.Theme.Data;
|
||||
using AtomUI.Theme.Styling;
|
||||
using AtomUI.Utils;
|
||||
|
@ -1,4 +1,5 @@
|
||||
using AtomUI.Controls.Primitives;
|
||||
using AtomUI.MotionScene;
|
||||
using AtomUI.Theme;
|
||||
using AtomUI.Theme.Styling;
|
||||
using AtomUI.Theme.Utils;
|
||||
|
@ -8,6 +8,8 @@
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.AddOnDecoratedInnerBoxTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.AlertTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.ArrowDecoratedBoxTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.Badge.CountBadgeAdornerTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.Badge.DotBadgeAdornerTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.ButtonSpinnerInnerBoxTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.ButtonSpinnerTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.DefaultButtonTheme());
|
||||
|
@ -64,6 +64,7 @@ namespace AtomUI.Theme.Styling
|
||||
public static readonly TokenResourceKey BadgeRibbonCornerTransform = new TokenResourceKey("Badge.BadgeRibbonCornerTransform", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey BadgeRibbonCornerDarkenAmount = new TokenResourceKey("Badge.BadgeRibbonCornerDarkenAmount", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey BadgeRibbonTextPadding = new TokenResourceKey("Badge.BadgeRibbonTextPadding", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey DotBadgeLabelMargin = new TokenResourceKey("Badge.DotBadgeLabelMargin", "AtomUI.Token");
|
||||
}
|
||||
|
||||
public static class ButtonSpinnerTokenResourceKey
|
||||
|
@ -1,6 +1,5 @@
|
||||
using AtomUI.Controls.Primitives;
|
||||
using AtomUI.Controls.Utils;
|
||||
using AtomUI.Icon;
|
||||
using AtomUI.Icon;
|
||||
using AtomUI.MotionScene;
|
||||
using AtomUI.Theme.Styling;
|
||||
using AtomUI.Utils;
|
||||
using Avalonia;
|
||||
|
@ -1,4 +1,5 @@
|
||||
using AtomUI.Controls.Primitives;
|
||||
using AtomUI.MotionScene;
|
||||
using AtomUI.Theme;
|
||||
using AtomUI.Theme.Styling;
|
||||
using AtomUI.Utils;
|
||||
|
@ -1,4 +1,5 @@
|
||||
using AtomUI.Controls.Primitives;
|
||||
using AtomUI.MotionScene;
|
||||
using AtomUI.Theme.Styling;
|
||||
using AtomUI.Theme.Utils;
|
||||
using AtomUI.Utils;
|
||||
|
@ -1,10 +1,9 @@
|
||||
using System.Windows.Input;
|
||||
using AtomUI.Controls.Primitives;
|
||||
using AtomUI.Controls.Utils;
|
||||
using AtomUI.Data;
|
||||
using AtomUI.Icon;
|
||||
using AtomUI.Input;
|
||||
using AtomUI.Media;
|
||||
using AtomUI.MotionScene;
|
||||
using AtomUI.Theme.Styling;
|
||||
using AtomUI.Theme.Utils;
|
||||
using AtomUI.Utils;
|
||||
@ -21,7 +20,6 @@ using Avalonia.Data;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.LogicalTree;
|
||||
using Avalonia.Media.Transformation;
|
||||
using Avalonia.Rendering;
|
||||
using Avalonia.VisualTree;
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
using AtomUI.Controls.Primitives;
|
||||
using AtomUI.Controls.Utils;
|
||||
using AtomUI.MotionScene;
|
||||
using AtomUI.Theme.Styling;
|
||||
using AtomUI.Utils;
|
||||
using Avalonia;
|
||||
@ -241,7 +240,7 @@ public class NotificationCard : ContentControl
|
||||
return;
|
||||
}
|
||||
|
||||
MotionConfig? motionConfig;
|
||||
MotionConfigX? motionConfig;
|
||||
if (Position == NotificationPosition.TopLeft || Position == NotificationPosition.BottomLeft)
|
||||
{
|
||||
motionConfig = MotionFactory.BuildMoveLeftInMotion(AnimationMaxOffsetX, _openCloseMotionDuration, new CubicEaseOut(),
|
||||
@ -276,7 +275,7 @@ public class NotificationCard : ContentControl
|
||||
{
|
||||
return;
|
||||
}
|
||||
MotionConfig? motionConfig;
|
||||
MotionConfigX? motionConfig;
|
||||
if (Position == NotificationPosition.TopLeft || Position == NotificationPosition.BottomLeft)
|
||||
{
|
||||
motionConfig = MotionFactory.BuildMoveLeftOutMotion(AnimationMaxOffsetX, _openCloseMotionDuration, new CubicEaseIn(),
|
||||
|
@ -1,5 +1,6 @@
|
||||
using AtomUI.Controls.Primitives;
|
||||
using AtomUI.Controls.Utils;
|
||||
using AtomUI.MotionScene;
|
||||
using AtomUI.Theme;
|
||||
using AtomUI.Theme.Styling;
|
||||
using AtomUI.Utils;
|
||||
|
@ -246,9 +246,9 @@ public class Separator : AvaloniaSeparator
|
||||
if (lineMinWidth > remainWidth)
|
||||
{
|
||||
// 字过多
|
||||
titleWidth = finalSize.Width - lineMinWidth;
|
||||
titleWidth = Math.Max(finalSize.Width - lineMinWidth, lineMinWidth);
|
||||
}
|
||||
|
||||
|
||||
// 处理完成之后,字的宽度一定在 width 范围内
|
||||
// 计算位置
|
||||
if (TitlePosition == SeparatorTitlePosition.Left)
|
||||
@ -267,7 +267,7 @@ public class Separator : AvaloniaSeparator
|
||||
var rightDelta = titleRect.Right - finalSize.Width;
|
||||
if (MathUtils.GreaterThan(rightDelta, 0))
|
||||
{
|
||||
titleRect = titleRect.WithWidth(finalSize.Width - titleRect.Left);
|
||||
titleRect = titleRect.WithWidth(Math.Max(finalSize.Width - titleRect.Left, lineMinWidth));
|
||||
}
|
||||
}
|
||||
else if (TitlePosition == SeparatorTitlePosition.Right)
|
||||
@ -297,7 +297,6 @@ public class Separator : AvaloniaSeparator
|
||||
new Size(titleWidth, finalSize.Height));
|
||||
}
|
||||
}
|
||||
|
||||
return titleRect;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
using AtomUI.Controls.Utils;
|
||||
using AtomUI.MotionScene;
|
||||
using AtomUI.Theme;
|
||||
using Avalonia;
|
||||
using Avalonia.Animation;
|
||||
|
@ -1,7 +1,4 @@
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using AtomUI.Controls.MotionScene;
|
||||
using AtomUI.MotionScene;
|
||||
using AtomUI.Utils;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
@ -279,7 +276,6 @@ internal class ThemeManager : Styles, IThemeManager
|
||||
|
||||
internal void Configure()
|
||||
{
|
||||
RegisterServices();
|
||||
RegisterControlThemes();
|
||||
BuildLanguageResources();
|
||||
}
|
||||
@ -330,13 +326,7 @@ internal class ThemeManager : Styles, IThemeManager
|
||||
{
|
||||
ControlTokenTypes.Add(tokenType);
|
||||
}
|
||||
|
||||
private void RegisterServices()
|
||||
{
|
||||
var motionDirector = new Director();
|
||||
AvaloniaLocator.CurrentMutable.Bind<IDirector>()
|
||||
.ToConstant(motionDirector);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class ThemeOperateEventArgs : EventArgs
|
||||
|
Loading…
Reference in New Issue
Block a user