完成 DotBadge 改造

This commit is contained in:
polarboy 2024-07-22 11:49:50 +08:00
parent fa9c19574a
commit e4ef5a9b59
7 changed files with 260 additions and 344 deletions

View File

@ -49,6 +49,10 @@ public partial class CountBadge : Control, IControlCustomStyle
public static readonly StyledProperty<bool> BadgeIsVisibleProperty = public static readonly StyledProperty<bool> BadgeIsVisibleProperty =
AvaloniaProperty.Register<CountBadge, bool>(nameof(BadgeIsVisible)); AvaloniaProperty.Register<CountBadge, bool>(nameof(BadgeIsVisible));
internal static readonly StyledProperty<TimeSpan> MotionDurationProperty =
AvaloniaProperty.Register<CountBadge, TimeSpan>(
nameof(MotionDuration));
public string? BadgeColor public string? BadgeColor
{ {
get => GetValue(BadgeColorProperty); get => GetValue(BadgeColorProperty);
@ -98,7 +102,12 @@ public partial class CountBadge : Control, IControlCustomStyle
set => SetValue(BadgeIsVisibleProperty, value); set => SetValue(BadgeIsVisibleProperty, value);
} }
private bool _initialized = false; public TimeSpan MotionDuration
{
get => GetValue(MotionDurationProperty);
set => SetValue(MotionDurationProperty, value);
}
private IControlCustomStyle _customStyle; private IControlCustomStyle _customStyle;
private CountBadgeAdorner? _badgeAdorner; private CountBadgeAdorner? _badgeAdorner;
private AdornerLayer? _adornerLayer; private AdornerLayer? _adornerLayer;
@ -118,17 +127,15 @@ public partial class CountBadge : Control, IControlCustomStyle
AffectsRender<CountBadge>(BadgeColorProperty, OffsetProperty); AffectsRender<CountBadge>(BadgeColorProperty, OffsetProperty);
} }
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e) public sealed override void ApplyTemplate()
{ {
base.OnAttachedToLogicalTree(e); base.ApplyTemplate();
if (!_initialized) { CreateBadgeAdorner();
_customStyle.HandleAttachedToLogicalTree(e);
_initialized = true;
}
} }
void IControlCustomStyle.HandleAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e) private void CreateBadgeAdorner()
{ {
if (_badgeAdorner is null) {
_badgeAdorner = new CountBadgeAdorner(); _badgeAdorner = new CountBadgeAdorner();
_customStyle.SetupTokenBindings(); _customStyle.SetupTokenBindings();
HandleDecoratedTargetChanged(); HandleDecoratedTargetChanged();
@ -136,20 +143,21 @@ public partial class CountBadge : Control, IControlCustomStyle
SetupBadgeColor(BadgeColor); SetupBadgeColor(BadgeColor);
} }
} }
}
private void PrepareAdorner() private void PrepareAdorner()
{ {
if (_adornerLayer is null && if (_adornerLayer is null && DecoratedTarget is not null) {
DecoratedTarget is not null && CreateBadgeAdorner();
_badgeAdorner is not null) { var badgeAdorner = _badgeAdorner!;
_adornerLayer = AdornerLayer.GetAdornerLayer(this); _adornerLayer = AdornerLayer.GetAdornerLayer(this);
// 这里需要抛出异常吗? // 这里需要抛出异常吗?
if (_adornerLayer == null) { if (_adornerLayer == null) {
return; return;
} }
AdornerLayer.SetAdornedElement(_badgeAdorner, this); AdornerLayer.SetAdornedElement(badgeAdorner, this);
AdornerLayer.SetIsClipEnabled(_badgeAdorner, false); AdornerLayer.SetIsClipEnabled(badgeAdorner, false);
_adornerLayer.Children.Add(_badgeAdorner); _adornerLayer.Children.Add(badgeAdorner);
} }
} }
@ -167,14 +175,14 @@ public partial class CountBadge : Control, IControlCustomStyle
var adorner = _badgeAdorner!; var adorner = _badgeAdorner!;
if (DecoratedTarget is not null) { if (DecoratedTarget is not null) {
var countBadgeZoomBadgeIn = new CountBadgeZoomBadgeIn(); var countBadgeZoomBadgeIn = new CountBadgeZoomBadgeIn();
countBadgeZoomBadgeIn.ConfigureOpacity(_motionDurationSlow); countBadgeZoomBadgeIn.ConfigureOpacity(MotionDuration);
countBadgeZoomBadgeIn.ConfigureRenderTransform(_motionDurationSlow); countBadgeZoomBadgeIn.ConfigureRenderTransform(MotionDuration);
motion = countBadgeZoomBadgeIn; motion = countBadgeZoomBadgeIn;
adorner.AnimationRenderTransformOrigin = motion.MotionRenderTransformOrigin; adorner.AnimationRenderTransformOrigin = motion.MotionRenderTransformOrigin;
} else { } else {
var countBadgeNoWrapperZoomBadgeIn = new CountBadgeNoWrapperZoomBadgeIn(); var countBadgeNoWrapperZoomBadgeIn = new CountBadgeNoWrapperZoomBadgeIn();
countBadgeNoWrapperZoomBadgeIn.ConfigureOpacity(_motionDurationSlow); countBadgeNoWrapperZoomBadgeIn.ConfigureOpacity(MotionDuration);
countBadgeNoWrapperZoomBadgeIn.ConfigureRenderTransform(_motionDurationSlow); countBadgeNoWrapperZoomBadgeIn.ConfigureRenderTransform(MotionDuration);
motion = countBadgeNoWrapperZoomBadgeIn; motion = countBadgeNoWrapperZoomBadgeIn;
} }
@ -209,14 +217,14 @@ public partial class CountBadge : Control, IControlCustomStyle
var adorner = _badgeAdorner!; var adorner = _badgeAdorner!;
if (DecoratedTarget is not null) { if (DecoratedTarget is not null) {
var countBadgeZoomBadgeOut = new CountBadgeZoomBadgeOut(); var countBadgeZoomBadgeOut = new CountBadgeZoomBadgeOut();
countBadgeZoomBadgeOut.ConfigureOpacity(_motionDurationSlow); countBadgeZoomBadgeOut.ConfigureOpacity(MotionDuration);
countBadgeZoomBadgeOut.ConfigureRenderTransform(_motionDurationSlow); countBadgeZoomBadgeOut.ConfigureRenderTransform(MotionDuration);
motion = countBadgeZoomBadgeOut; motion = countBadgeZoomBadgeOut;
adorner.AnimationRenderTransformOrigin = motion.MotionRenderTransformOrigin; adorner.AnimationRenderTransformOrigin = motion.MotionRenderTransformOrigin;
} else { } else {
var countBadgeNoWrapperZoomBadgeOut = new CountBadgeNoWrapperZoomBadgeOut(); var countBadgeNoWrapperZoomBadgeOut = new CountBadgeNoWrapperZoomBadgeOut();
countBadgeNoWrapperZoomBadgeOut.ConfigureOpacity(_motionDurationSlow); countBadgeNoWrapperZoomBadgeOut.ConfigureOpacity(MotionDuration);
countBadgeNoWrapperZoomBadgeOut.ConfigureRenderTransform(_motionDurationSlow); countBadgeNoWrapperZoomBadgeOut.ConfigureRenderTransform(MotionDuration);
motion = countBadgeNoWrapperZoomBadgeOut; motion = countBadgeNoWrapperZoomBadgeOut;
} }
@ -251,20 +259,20 @@ public partial class CountBadge : Control, IControlCustomStyle
BindUtils.RelayBind(this, OverflowCountProperty, _badgeAdorner, CountBadgeAdorner.OverflowCountProperty); BindUtils.RelayBind(this, OverflowCountProperty, _badgeAdorner, CountBadgeAdorner.OverflowCountProperty);
BindUtils.RelayBind(this, CountProperty, _badgeAdorner, CountBadgeAdorner.CountProperty); BindUtils.RelayBind(this, CountProperty, _badgeAdorner, CountBadgeAdorner.CountProperty);
} }
BindUtils.CreateTokenBinding(this, MotionDurationSlowTokenProperty, GlobalResourceKey.MotionDurationSlow); BindUtils.CreateTokenBinding(this, MotionDurationProperty, GlobalResourceKey.MotionDurationSlow);
} }
private void HandleDecoratedTargetChanged() private void HandleDecoratedTargetChanged()
{ {
if (_badgeAdorner is not null) { if (_badgeAdorner is not null) {
if (DecoratedTarget is null) { if (DecoratedTarget is null) {
((ISetLogicalParent)_badgeAdorner).SetParent(this);
VisualChildren.Add(_badgeAdorner); VisualChildren.Add(_badgeAdorner);
LogicalChildren.Add(_badgeAdorner);
_badgeAdorner.IsAdornerMode = false; _badgeAdorner.IsAdornerMode = false;
} else if (DecoratedTarget is not null) { } else if (DecoratedTarget is not null) {
_badgeAdorner.IsAdornerMode = true; _badgeAdorner.IsAdornerMode = true;
((ISetLogicalParent)DecoratedTarget).SetParent(this);
VisualChildren.Add(DecoratedTarget); VisualChildren.Add(DecoratedTarget);
LogicalChildren.Add(DecoratedTarget);
} }
} }
} }
@ -293,7 +301,7 @@ public partial class CountBadge : Control, IControlCustomStyle
HideAdornerWithMotion(); HideAdornerWithMotion();
} }
} }
if (_initialized) { if (VisualRoot is not null) {
if (e.Property == DecoratedTargetProperty) { if (e.Property == DecoratedTargetProperty) {
HandleDecoratedTargetChanged(); HandleDecoratedTargetChanged();
} }

View File

@ -1,8 +1,6 @@
using System.Globalization; using System.Globalization;
using AtomUI.Data;
using AtomUI.Media; using AtomUI.Media;
using AtomUI.Styling; using AtomUI.Styling;
using AtomUI.Utils;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Documents; using Avalonia.Controls.Documents;
@ -14,7 +12,7 @@ using Avalonia.Styling;
namespace AtomUI.Controls; namespace AtomUI.Controls;
internal partial class CountBadgeAdorner : Control, IControlCustomStyle internal class CountBadgeAdorner : Control, IControlCustomStyle
{ {
public static readonly StyledProperty<IBrush?> BadgeColorProperty = public static readonly StyledProperty<IBrush?> BadgeColorProperty =
AvaloniaProperty.Register<CountBadgeAdorner, IBrush?>( AvaloniaProperty.Register<CountBadgeAdorner, IBrush?>(
@ -114,20 +112,28 @@ internal partial class CountBadgeAdorner : Control, IControlCustomStyle
set => SetValue(PaddingInlineProperty, value); set => SetValue(PaddingInlineProperty, value);
} }
internal bool IsAdornerMode { get; set; } internal static readonly DirectProperty<DotBadgeAdorner, bool> IsAdornerModeProperty =
AvaloniaProperty.RegisterDirect<DotBadgeAdorner, bool>(
nameof(IsAdornerMode),
o => o.IsAdornerMode,
(o, v) => o.IsAdornerMode = v);
public static readonly DirectProperty<CountBadgeAdorner, Point> OffsetProperty = private bool _isAdornerMode = false;
AvaloniaProperty.RegisterDirect<CountBadgeAdorner, Point>(
nameof(Offset),
o => o.Offset,
(o, v) => o.Offset = v);
private Point _offset; internal bool IsAdornerMode
{
get => _isAdornerMode;
set => SetAndRaise(IsAdornerModeProperty, ref _isAdornerMode, value);
}
internal static readonly StyledProperty<Point> OffsetProperty =
AvaloniaProperty.Register<CountBadgeAdorner, Point>(
nameof(Offset));
public Point Offset public Point Offset
{ {
get => _offset; get => GetValue(OffsetProperty);
set => SetAndRaise(OffsetProperty, ref _offset, value); set => SetValue(OffsetProperty, value);
} }
public static readonly DirectProperty<CountBadgeAdorner, int> OverflowCountProperty = public static readonly DirectProperty<CountBadgeAdorner, int> OverflowCountProperty =
@ -166,7 +172,8 @@ internal partial class CountBadgeAdorner : Control, IControlCustomStyle
{ {
AffectsMeasure<CountBadgeAdorner>(OverflowCountProperty, AffectsMeasure<CountBadgeAdorner>(OverflowCountProperty,
SizeProperty, SizeProperty,
CountProperty); CountProperty,
IsAdornerModeProperty);
AffectsRender<CountBadgeAdorner>(BadgeColorProperty, OffsetProperty); AffectsRender<CountBadgeAdorner>(BadgeColorProperty, OffsetProperty);
} }
@ -212,7 +219,6 @@ internal partial class CountBadgeAdorner : Control, IControlCustomStyle
smallSizeStyle.Add(TextFontSizeProperty, BadgeResourceKey.TextFontSizeSM); smallSizeStyle.Add(TextFontSizeProperty, BadgeResourceKey.TextFontSizeSM);
smallSizeStyle.Add(IndicatorHeightProperty, BadgeResourceKey.IndicatorHeightSM); smallSizeStyle.Add(IndicatorHeightProperty, BadgeResourceKey.IndicatorHeightSM);
Styles.Add(smallSizeStyle); Styles.Add(smallSizeStyle);
} }
public override void ApplyTemplate() public override void ApplyTemplate()

View File

@ -1,17 +0,0 @@
using Avalonia;
namespace AtomUI.Controls;
public partial class CountBadge
{
#region Control token
private TimeSpan _motionDurationSlow;
private static readonly DirectProperty<CountBadge, TimeSpan> MotionDurationSlowTokenProperty =
AvaloniaProperty.RegisterDirect<CountBadge, TimeSpan>(
nameof(_motionDurationSlow),
o => o._motionDurationSlow,
(o, v) => o._motionDurationSlow = v);
#endregion
}

View File

@ -46,6 +46,10 @@ public partial class DotBadge : Control, IControlCustomStyle
public static readonly StyledProperty<bool> BadgeIsVisibleProperty = public static readonly StyledProperty<bool> BadgeIsVisibleProperty =
AvaloniaProperty.Register<DotBadge, bool>(nameof(BadgeIsVisible)); AvaloniaProperty.Register<DotBadge, bool>(nameof(BadgeIsVisible));
internal static readonly StyledProperty<TimeSpan> MotionDurationProperty =
AvaloniaProperty.Register<CountBadge, TimeSpan>(
nameof(MotionDuration));
public string? DotColor public string? DotColor
{ {
get => GetValue(DotColorProperty); get => GetValue(DotColorProperty);
@ -83,6 +87,12 @@ public partial class DotBadge : Control, IControlCustomStyle
set => SetValue(BadgeIsVisibleProperty, value); set => SetValue(BadgeIsVisibleProperty, value);
} }
public TimeSpan MotionDuration
{
get => GetValue(MotionDurationProperty);
set => SetValue(MotionDurationProperty, value);
}
private bool _initialized = false; private bool _initialized = false;
private IControlCustomStyle _customStyle; private IControlCustomStyle _customStyle;
private DotBadgeAdorner? _dotBadgeAdorner; private DotBadgeAdorner? _dotBadgeAdorner;
@ -96,39 +106,41 @@ public partial class DotBadge : Control, IControlCustomStyle
static DotBadge() static DotBadge()
{ {
AffectsMeasure<DotBadge>(DecoratedTargetProperty, AffectsMeasure<DotBadge>(DecoratedTargetProperty, TextProperty);
TextProperty);
AffectsRender<DotBadge>(DotColorProperty, StatusProperty); AffectsRender<DotBadge>(DotColorProperty, StatusProperty);
} }
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
{
base.OnAttachedToLogicalTree(e);
if (!_initialized) {
_customStyle.SetupUI();
_initialized = true;
}
}
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{ {
base.OnAttachedToVisualTree(e); base.OnAttachedToVisualTree(e);
PrepareAdorner(); PrepareAdorner();
} }
private void CreateDotBadgeAdorner()
{
if (_dotBadgeAdorner is null) {
_dotBadgeAdorner = new DotBadgeAdorner();
_customStyle.SetupTokenBindings();
HandleDecoratedTargetChanged();
if (DotColor is not null) {
SetupDotColor(DotColor);
}
}
}
private void PrepareAdorner() private void PrepareAdorner()
{ {
if (_adornerLayer is null && if (_adornerLayer is null && DecoratedTarget is not null) {
DecoratedTarget is not null && CreateDotBadgeAdorner();
_dotBadgeAdorner is not null) { var dotBadgeAdorner = _dotBadgeAdorner!;
_adornerLayer = AdornerLayer.GetAdornerLayer(this); _adornerLayer = AdornerLayer.GetAdornerLayer(this);
// 这里需要抛出异常吗? // 这里需要抛出异常吗?
if (_adornerLayer == null) { if (_adornerLayer == null) {
return; return;
} }
AdornerLayer.SetAdornedElement(_dotBadgeAdorner, this); AdornerLayer.SetAdornedElement(dotBadgeAdorner, this);
AdornerLayer.SetIsClipEnabled(_dotBadgeAdorner, false); AdornerLayer.SetIsClipEnabled(dotBadgeAdorner, false);
_adornerLayer.Children.Add(_dotBadgeAdorner); _adornerLayer.Children.Add(dotBadgeAdorner);
} }
} }
@ -142,8 +154,8 @@ public partial class DotBadge : Control, IControlCustomStyle
_animating = true; _animating = true;
var director = Director.Instance; var director = Director.Instance;
var motion = new CountBadgeZoomBadgeIn(); var motion = new CountBadgeZoomBadgeIn();
motion.ConfigureOpacity(_motionDurationSlow); motion.ConfigureOpacity(MotionDuration);
motion.ConfigureRenderTransform(_motionDurationSlow); motion.ConfigureRenderTransform(MotionDuration);
_dotBadgeAdorner!.AnimationRenderTransformOrigin = motion.MotionRenderTransformOrigin; _dotBadgeAdorner!.AnimationRenderTransformOrigin = motion.MotionRenderTransformOrigin;
var motionActor = new MotionActor(_dotBadgeAdorner, motion); var motionActor = new MotionActor(_dotBadgeAdorner, motion);
motionActor.DispatchInSceneLayer = false; motionActor.DispatchInSceneLayer = false;
@ -174,8 +186,8 @@ public partial class DotBadge : Control, IControlCustomStyle
_animating = true; _animating = true;
var director = Director.Instance; var director = Director.Instance;
var motion = new CountBadgeZoomBadgeOut(); var motion = new CountBadgeZoomBadgeOut();
motion.ConfigureOpacity(_motionDurationSlow); motion.ConfigureOpacity(MotionDuration);
motion.ConfigureRenderTransform(_motionDurationSlow); motion.ConfigureRenderTransform(MotionDuration);
_dotBadgeAdorner!.AnimationRenderTransformOrigin = motion.MotionRenderTransformOrigin; _dotBadgeAdorner!.AnimationRenderTransformOrigin = motion.MotionRenderTransformOrigin;
var motionActor = new MotionActor(_dotBadgeAdorner, motion); var motionActor = new MotionActor(_dotBadgeAdorner, motion);
motionActor.DispatchInSceneLayer = false; motionActor.DispatchInSceneLayer = false;
@ -195,16 +207,6 @@ public partial class DotBadge : Control, IControlCustomStyle
HideAdorner(); HideAdorner();
} }
void IControlCustomStyle.SetupUI()
{
_dotBadgeAdorner = new DotBadgeAdorner();
_customStyle.SetupTokenBindings();
HandleDecoratedTargetChanged();
if (DotColor is not null) {
SetupDotColor(DotColor);
}
}
void IControlCustomStyle.SetupTokenBindings() void IControlCustomStyle.SetupTokenBindings()
{ {
if (_dotBadgeAdorner is not null) { if (_dotBadgeAdorner is not null) {
@ -212,24 +214,30 @@ public partial class DotBadge : Control, IControlCustomStyle
BindUtils.RelayBind(this, TextProperty, _dotBadgeAdorner, DotBadgeAdorner.TextProperty); BindUtils.RelayBind(this, TextProperty, _dotBadgeAdorner, DotBadgeAdorner.TextProperty);
BindUtils.RelayBind(this, OffsetProperty, _dotBadgeAdorner, DotBadgeAdorner.OffsetProperty); BindUtils.RelayBind(this, OffsetProperty, _dotBadgeAdorner, DotBadgeAdorner.OffsetProperty);
} }
BindUtils.CreateTokenBinding(this, MotionDurationSlowTokenProperty, GlobalResourceKey.MotionDurationSlow); BindUtils.CreateTokenBinding(this, MotionDurationProperty, GlobalResourceKey.MotionDurationSlow);
} }
private void HandleDecoratedTargetChanged() private void HandleDecoratedTargetChanged()
{ {
if (_dotBadgeAdorner is not null) { if (_dotBadgeAdorner is not null) {
if (DecoratedTarget is null) { if (DecoratedTarget is null) {
VisualChildren.Add(_dotBadgeAdorner);
LogicalChildren.Add(_dotBadgeAdorner);
_dotBadgeAdorner.IsAdornerMode = false; _dotBadgeAdorner.IsAdornerMode = false;
((ISetLogicalParent)_dotBadgeAdorner).SetParent(this);
VisualChildren.Add(_dotBadgeAdorner);
} else if (DecoratedTarget is not null) { } else if (DecoratedTarget is not null) {
_dotBadgeAdorner.IsAdornerMode = true; _dotBadgeAdorner.IsAdornerMode = true;
VisualChildren.Add(DecoratedTarget); VisualChildren.Add(DecoratedTarget);
LogicalChildren.Add(DecoratedTarget); ((ISetLogicalParent)DecoratedTarget).SetParent(this);
} }
} }
} }
public sealed override void ApplyTemplate()
{
base.ApplyTemplate();
CreateDotBadgeAdorner();
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs e) protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs e)
{ {
base.OnPropertyChanged(e); base.OnPropertyChanged(e);
@ -281,12 +289,12 @@ public partial class DotBadge : Control, IControlCustomStyle
foreach (var presetColor in PresetPrimaryColor.AllColorTypes()) { foreach (var presetColor in PresetPrimaryColor.AllColorTypes()) {
if (presetColor.Type.ToString().ToLower() == colorStr) { if (presetColor.Type.ToString().ToLower() == colorStr) {
_dotBadgeAdorner!.DotColor = new SolidColorBrush(presetColor.Color()); _dotBadgeAdorner!.BadgeDotColor = new SolidColorBrush(presetColor.Color());
return; return;
} }
} }
if (Color.TryParse(colorStr, out Color color)) { if (Color.TryParse(colorStr, out Color color)) {
_dotBadgeAdorner!.DotColor = new SolidColorBrush(color); _dotBadgeAdorner!.BadgeDotColor = new SolidColorBrush(color);
} }
} }
} }

View File

@ -5,24 +5,12 @@ using Avalonia.Controls;
using Avalonia.Layout; using Avalonia.Layout;
using Avalonia.LogicalTree; using Avalonia.LogicalTree;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Styling;
namespace AtomUI.Controls; namespace AtomUI.Controls;
internal partial class DotBadgeAdorner : Control, IControlCustomStyle internal partial class DotBadgeAdorner : Control, IControlCustomStyle
{ {
public static readonly DirectProperty<DotBadgeAdorner, IBrush?> DotColorProperty =
AvaloniaProperty.RegisterDirect<DotBadgeAdorner, IBrush?>(
nameof(DotColor),
o => o.DotColor,
(o, v) => o.DotColor = v);
private IBrush? _dotColor;
public IBrush? DotColor
{
get => _dotColor;
set => SetAndRaise(DotColorProperty, ref _dotColor, value);
}
public static readonly DirectProperty<DotBadgeAdorner, DotBadgeStatus?> StatusProperty = public static readonly DirectProperty<DotBadgeAdorner, DotBadgeStatus?> StatusProperty =
AvaloniaProperty.RegisterDirect<DotBadgeAdorner, DotBadgeStatus?>( AvaloniaProperty.RegisterDirect<DotBadgeAdorner, DotBadgeStatus?>(
nameof(Status), nameof(Status),
@ -55,6 +43,34 @@ internal partial class DotBadgeAdorner : Control, IControlCustomStyle
o => o.IsAdornerMode, o => o.IsAdornerMode,
(o, v) => o.IsAdornerMode = v); (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));
private bool _isAdornerMode = false; private bool _isAdornerMode = false;
public bool IsAdornerMode public bool IsAdornerMode
{ {
@ -62,33 +78,46 @@ internal partial class DotBadgeAdorner : Control, IControlCustomStyle
set => SetAndRaise(IsAdornerModeProperty, ref _isAdornerMode, value); set => SetAndRaise(IsAdornerModeProperty, ref _isAdornerMode, value);
} }
public static readonly DirectProperty<DotBadgeAdorner, IBrush?> EffectiveDotColorProperty =
AvaloniaProperty.RegisterDirect<DotBadgeAdorner, IBrush?>(
nameof(EffectiveDotColor),
o => o.EffectiveDotColor,
(o, v) => o.EffectiveDotColor = v);
private IBrush? _effectiveDotColor;
// 当前有效的颜色
public IBrush? EffectiveDotColor
{
get => _effectiveDotColor;
set => SetAndRaise(EffectiveDotColorProperty, ref _effectiveDotColor, value);
}
public static readonly DirectProperty<DotBadgeAdorner, Point> OffsetProperty =
AvaloniaProperty.RegisterDirect<DotBadgeAdorner, Point>(
nameof(Offset),
o => o.Offset,
(o, v) => o.Offset = v);
private Point _offset;
public Point Offset public Point Offset
{ {
get => _offset; get => GetValue(OffsetProperty);
set => SetAndRaise(OffsetProperty, ref _offset, value); set => SetValue(OffsetProperty,value);
}
public double DotSize
{
get => GetValue(DotSizeProperty);
set => SetValue(DotSizeProperty, 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 = false; private bool _initialized = false;
@ -102,7 +131,7 @@ internal partial class DotBadgeAdorner : Control, IControlCustomStyle
static DotBadgeAdorner() static DotBadgeAdorner()
{ {
AffectsMeasure<DotBadge>(TextProperty, IsAdornerModeProperty); AffectsMeasure<DotBadge>(TextProperty, IsAdornerModeProperty);
AffectsRender<DotBadge>(EffectiveDotColorProperty, OffsetProperty); AffectsRender<DotBadge>(BadgeDotColorProperty, OffsetProperty);
} }
public DotBadgeAdorner() public DotBadgeAdorner()
@ -110,8 +139,10 @@ internal partial class DotBadgeAdorner : Control, IControlCustomStyle
_customStyle = this; _customStyle = this;
} }
void IControlCustomStyle.SetupUI() public sealed override void ApplyTemplate()
{ {
base.ApplyTemplate();
if (!_initialized) {
_textLabel = new Label _textLabel = new Label
{ {
Content = Text, Content = Text,
@ -122,64 +153,57 @@ internal partial class DotBadgeAdorner : Control, IControlCustomStyle
Padding = new Thickness(0), Padding = new Thickness(0),
}; };
LogicalChildren.Add(_textLabel); ((ISetLogicalParent)_textLabel).SetParent(this);
VisualChildren.Add(_textLabel); VisualChildren.Add(_textLabel);
_customStyle.SetupTokenBindings();
SetupEffectiveDotColor();
BuildBoxShadow(); BuildBoxShadow();
_initialized = true;
} }
void IControlCustomStyle.SetupTokenBindings()
{
BindUtils.CreateTokenBinding(this, ColorTextPlaceholderTokenProperty, GlobalResourceKey.ColorTextPlaceholder);
BindUtils.CreateTokenBinding(this, ColorErrorTokenProperty, GlobalResourceKey.ColorError);
BindUtils.CreateTokenBinding(this, ColorWarningTokenProperty, GlobalResourceKey.ColorWarning);
BindUtils.CreateTokenBinding(this, ColorSuccessTokenProperty, GlobalResourceKey.ColorSuccess);
BindUtils.CreateTokenBinding(this, ColorInfoTokenProperty, GlobalResourceKey.ColorInfo);
BindUtils.CreateTokenBinding(this, MarginXSTokenProperty, GlobalResourceKey.MarginXS);
BindUtils.CreateTokenBinding(this, DotSizeTokenProperty, BadgeResourceKey.DotSize);
BindUtils.CreateTokenBinding(this, StatusSizeTokenProperty, BadgeResourceKey.StatusSize);
BindUtils.CreateTokenBinding(this, BadgeColorTokenProperty, BadgeResourceKey.BadgeColor);
BindUtils.CreateTokenBinding(this, BadgeShadowSizeTokenProperty, BadgeResourceKey.BadgeShadowSize);
BindUtils.CreateTokenBinding(this, BadgeShadowColorTokenProperty, BadgeResourceKey.BadgeShadowColor);
} }
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e) protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
{ {
base.OnAttachedToLogicalTree(e); base.OnAttachedToLogicalTree(e);
if (!_initialized) { _customStyle.BuildStyles();
_customStyle.SetupUI();
_initialized = true;
}
} }
private IBrush? GetStatusColor(DotBadgeStatus status) void IControlCustomStyle.BuildStyles()
{ {
if (status == DotBadgeStatus.Error) { if (Styles.Count == 0) {
return _colorErrorToken; BuildBadgeColorStyle();
} else if (status == DotBadgeStatus.Processing) {
return _colorInfoToken;
} else if (status == DotBadgeStatus.Success) {
return _colorSuccessToken;
} else if (status == DotBadgeStatus.Warning) {
return _colorWarningToken;
} else {
return _colorTextPlaceholderToken;
} }
} }
private void SetupEffectiveDotColor() private void BuildBadgeColorStyle()
{ {
if (_dotColor is not null) { var commonStyle = new Style(selector => selector.OfType<DotBadgeAdorner>());
EffectiveDotColor = _dotColor; commonStyle.Add(BadgeTextMarginInlineProperty, GlobalResourceKey.MarginXS);
} else if (Status.HasValue) { commonStyle.Add(BadgeDotColorProperty, BadgeResourceKey.BadgeColor);
EffectiveDotColor = GetStatusColor(Status.Value); commonStyle.Add(DotSizeProperty, BadgeResourceKey.DotSize);
} commonStyle.Add(StatusSizeProperty, BadgeResourceKey.StatusSize);
commonStyle.Add(BadgeShadowSizeProperty, BadgeResourceKey.BadgeShadowSize);
commonStyle.Add(BadgeShadowColorProperty, BadgeResourceKey.BadgeShadowColor);
if (EffectiveDotColor is null) { var errorStatusStyle = new Style(selector => selector.Nesting().PropertyEquals(DotBadgeAdorner.StatusProperty, DotBadgeStatus.Error));
EffectiveDotColor = _badgeColorToken; errorStatusStyle.Add(DotBadgeAdorner.BadgeDotColorProperty, GlobalResourceKey.ColorError);
} commonStyle.Add(errorStatusStyle);
var successStatusStyle = new Style(selector => selector.Nesting().PropertyEquals(DotBadgeAdorner.StatusProperty, DotBadgeStatus.Success));
successStatusStyle.Add(DotBadgeAdorner.BadgeDotColorProperty, GlobalResourceKey.ColorSuccess);
commonStyle.Add(successStatusStyle);
var warningStatusStyle = new Style(selector => selector.Nesting().PropertyEquals(DotBadgeAdorner.StatusProperty, DotBadgeStatus.Warning));
warningStatusStyle.Add(DotBadgeAdorner.BadgeDotColorProperty, GlobalResourceKey.ColorWarning);
commonStyle.Add(warningStatusStyle);
var defaultStatusStyle = new Style(selector => selector.Nesting().PropertyEquals(DotBadgeAdorner.StatusProperty, DotBadgeStatus.Default));
defaultStatusStyle.Add(DotBadgeAdorner.BadgeDotColorProperty, GlobalResourceKey.ColorTextPlaceholder);
commonStyle.Add(defaultStatusStyle);
var processingStatusStyle = new Style(selector => selector.Nesting().PropertyEquals(DotBadgeAdorner.StatusProperty, DotBadgeStatus.Processing));
processingStatusStyle.Add(DotBadgeAdorner.BadgeDotColorProperty, GlobalResourceKey.ColorInfo);
commonStyle.Add(processingStatusStyle);
Styles.Add(commonStyle);
} }
protected override Size MeasureOverride(Size availableSize) protected override Size MeasureOverride(Size availableSize)
@ -191,11 +215,11 @@ internal partial class DotBadgeAdorner : Control, IControlCustomStyle
targetHeight = availableSize.Height; targetHeight = availableSize.Height;
} else { } else {
var textSize = base.MeasureOverride(availableSize); var textSize = base.MeasureOverride(availableSize);
targetWidth += _statusSizeToken; targetWidth += StatusSize;
targetWidth += textSize.Width; targetWidth += textSize.Width;
targetHeight += Math.Max(textSize.Height, _statusSizeToken); targetHeight += Math.Max(textSize.Height, StatusSize);
if (textSize.Width > 0) { if (textSize.Width > 0) {
targetWidth += _marginXSToken; targetWidth += BadgeTextMarginInline;
} }
} }
return new Size(targetWidth, targetHeight); return new Size(targetWidth, targetHeight);
@ -206,12 +230,12 @@ internal partial class DotBadgeAdorner : Control, IControlCustomStyle
if (!IsAdornerMode) { if (!IsAdornerMode) {
double textOffsetX = 0; double textOffsetX = 0;
if (IsAdornerMode) { if (IsAdornerMode) {
textOffsetX += _dotSizeToken; textOffsetX += DotSize;
} else { } else {
textOffsetX += _statusSizeToken; textOffsetX += StatusSize;
} }
textOffsetX += _marginXSToken; textOffsetX += BadgeTextMarginInline;
var textRect = new Rect(new Point(textOffsetX, 0), _textLabel!.DesiredSize); var textRect = new Rect(new Point(textOffsetX, 0), _textLabel!.DesiredSize);
_textLabel.Arrange(textRect); _textLabel.Arrange(textRect);
} }
@ -226,26 +250,19 @@ internal partial class DotBadgeAdorner : Control, IControlCustomStyle
if (_textLabel is not null) { if (_textLabel is not null) {
_textLabel.IsVisible = !newValue; _textLabel.IsVisible = !newValue;
} }
} else if (e.Property == BadgeShadowSizeTokenProperty || } else if (e.Property == BadgeShadowSizeProperty ||
e.Property == BadgeShadowColorTokenProperty) { e.Property == BadgeShadowColorProperty) {
BuildBoxShadow(); BuildBoxShadow();
} }
if (_initialized) {
if (e.Property == StatusProperty ||
e.Property == DotColorProperty) {
SetupEffectiveDotColor();
}
}
} }
public override void Render(DrawingContext context) public override void Render(DrawingContext context)
{ {
var dotSize = 0d; var dotSize = 0d;
if (IsAdornerMode) { if (IsAdornerMode) {
dotSize = _dotSizeToken; dotSize = DotSize;
} else { } else {
dotSize = _statusSizeToken; dotSize = StatusSize;
} }
var offsetX = 0d; var offsetX = 0d;
@ -273,19 +290,20 @@ internal partial class DotBadgeAdorner : Control, IControlCustomStyle
var renderTransform = (-offset) * RenderTransform.Value * (offset); var renderTransform = (-offset) * RenderTransform.Value * (offset);
context.PushTransform(renderTransform); context.PushTransform(renderTransform);
} }
context.DrawRectangle(BadgeDotColor, null, dotRect, dotSize, dotSize, _boxShadows);
context.DrawRectangle(EffectiveDotColor, null, dotRect, dotSize, dotSize, _boxShadows);
} }
private void BuildBoxShadow() private void BuildBoxShadow()
{ {
if (IsSet(BadgeShadowSizeProperty) && IsSet(BadgeShadowColorProperty)) {
_boxShadows = new BoxShadows(new BoxShadow() _boxShadows = new BoxShadows(new BoxShadow()
{ {
OffsetX = 0, OffsetX = 0,
OffsetY = 0, OffsetY = 0,
Blur = 0, Blur = 0,
Spread = _badgeShadowSizeToken, Spread = BadgeShadowSize,
Color = ((SolidColorBrush)_badgeShadowColorToken!).Color Color = ((SolidColorBrush)BadgeShadowColor!).Color
}); });
} }
} }
}

View File

@ -1,90 +0,0 @@
using Avalonia;
using Avalonia.Media;
namespace AtomUI.Controls;
internal partial class DotBadgeAdorner
{
#region Control token
private IBrush? _colorTextPlaceholderToken;
private static readonly DirectProperty<DotBadgeAdorner, IBrush?> ColorTextPlaceholderTokenProperty =
AvaloniaProperty.RegisterDirect<DotBadgeAdorner, IBrush?>(
nameof(_colorTextPlaceholderToken),
o => o._colorTextPlaceholderToken,
(o, v) => o._colorTextPlaceholderToken = v);
private IBrush? _colorErrorToken;
private static readonly DirectProperty<DotBadgeAdorner, IBrush?> ColorErrorTokenProperty =
AvaloniaProperty.RegisterDirect<DotBadgeAdorner, IBrush?>(
nameof(_colorErrorToken),
o => o._colorErrorToken,
(o, v) => o._colorErrorToken = v);
private IBrush? _colorWarningToken;
private static readonly DirectProperty<DotBadgeAdorner, IBrush?> ColorWarningTokenProperty =
AvaloniaProperty.RegisterDirect<DotBadgeAdorner, IBrush?>(
nameof(_colorWarningToken),
o => o._colorWarningToken,
(o, v) => o._colorWarningToken = v);
private IBrush? _colorSuccessToken;
private static readonly DirectProperty<DotBadgeAdorner, IBrush?> ColorSuccessTokenProperty =
AvaloniaProperty.RegisterDirect<DotBadgeAdorner, IBrush?>(
nameof(_colorSuccessToken),
o => o._colorSuccessToken,
(o, v) => o._colorSuccessToken = v);
private IBrush? _colorInfoToken;
private static readonly DirectProperty<DotBadgeAdorner, IBrush?> ColorInfoTokenProperty =
AvaloniaProperty.RegisterDirect<DotBadgeAdorner, IBrush?>(
nameof(_colorInfoToken),
o => o._colorInfoToken,
(o, v) => o._colorInfoToken = v);
private double _dotSizeToken;
private static readonly DirectProperty<DotBadgeAdorner, double> DotSizeTokenProperty =
AvaloniaProperty.RegisterDirect<DotBadgeAdorner, double>(
nameof(_dotSizeToken),
o => o._dotSizeToken,
(o, v) => o._dotSizeToken = v);
private double _statusSizeToken;
private static readonly DirectProperty<DotBadgeAdorner, double> StatusSizeTokenProperty =
AvaloniaProperty.RegisterDirect<DotBadgeAdorner, double>(
nameof(_statusSizeToken),
o => o._statusSizeToken,
(o, v) => o._statusSizeToken = v);
private double _marginXSToken;
private static readonly DirectProperty<DotBadgeAdorner, double> MarginXSTokenProperty =
AvaloniaProperty.RegisterDirect<DotBadgeAdorner, double>(
nameof(_marginXSToken),
o => o._marginXSToken,
(o, v) => o._marginXSToken = v);
private IBrush? _badgeColorToken;
private static readonly DirectProperty<DotBadgeAdorner, IBrush?> BadgeColorTokenProperty =
AvaloniaProperty.RegisterDirect<DotBadgeAdorner, IBrush?>(
nameof(_badgeColorToken),
o => o._badgeColorToken,
(o, v) => o._badgeColorToken = v);
private IBrush? _badgeShadowColorToken;
private static readonly DirectProperty<DotBadgeAdorner, IBrush?> BadgeShadowColorTokenProperty =
AvaloniaProperty.RegisterDirect<DotBadgeAdorner, IBrush?>(
nameof(_badgeShadowColorToken),
o => o._badgeShadowColorToken,
(o, v) => o._badgeShadowColorToken = v);
private double _badgeShadowSizeToken;
private static readonly DirectProperty<DotBadgeAdorner, double> BadgeShadowSizeTokenProperty =
AvaloniaProperty.RegisterDirect<DotBadgeAdorner, double>(
nameof(_badgeShadowSizeToken),
o => o._badgeShadowSizeToken,
(o, v) => o._badgeShadowSizeToken = v);
#endregion
}

View File

@ -1,17 +0,0 @@
using Avalonia;
namespace AtomUI.Controls;
public partial class DotBadge
{
#region Control token
private TimeSpan _motionDurationSlow;
private static readonly DirectProperty<DotBadge, TimeSpan> MotionDurationSlowTokenProperty =
AvaloniaProperty.RegisterDirect<DotBadge, TimeSpan>(
nameof(_motionDurationSlow),
o => o._motionDurationSlow,
(o, v) => o._motionDurationSlow = v);
#endregion
}