完成 ArrowDecoratedBox 风格化改造

This commit is contained in:
polarboy 2024-07-22 00:56:07 +08:00
parent 1f17287cdb
commit a7726f4f58
8 changed files with 61 additions and 95 deletions

View File

@ -94,6 +94,8 @@ public class ArrowDecoratedBox : TemplatedControl,
public static readonly StyledProperty<Control?> ChildProperty = public static readonly StyledProperty<Control?> ChildProperty =
Border.ChildProperty.AddOwner<ArrowDecoratedBox>(); Border.ChildProperty.AddOwner<ArrowDecoratedBox>();
internal static readonly StyledProperty<double> ArrowSizeProperty
= AvaloniaProperty.Register<ArrowDecoratedBox, double>(nameof(ArrowSize));
// 指针最顶点位置 // 指针最顶点位置
// 相对坐标 // 相对坐标
@ -117,6 +119,15 @@ public class ArrowDecoratedBox : TemplatedControl,
get => GetValue(ArrowPositionProperty); get => GetValue(ArrowPositionProperty);
set => SetValue(ArrowPositionProperty, value); set => SetValue(ArrowPositionProperty, value);
} }
/// <summary>
/// 箭头的大小
/// </summary>
internal double ArrowSize
{
get => GetValue(ArrowSizeProperty);
set => SetValue(ArrowSizeProperty, value);
}
/// <summary> /// <summary>
/// Gets or sets the decorated control. /// Gets or sets the decorated control.
@ -133,8 +144,6 @@ public class ArrowDecoratedBox : TemplatedControl,
private Geometry? _arrowGeometry; private Geometry? _arrowGeometry;
private Rect _contentRect; private Rect _contentRect;
private Rect _arrowRect; private Rect _arrowRect;
private Border? _container;
private CompositeDisposable? _compositeDisposable;
private bool _needGenerateArrowVertexPoint = true; private bool _needGenerateArrowVertexPoint = true;
static ArrowDecoratedBox() static ArrowDecoratedBox()
@ -171,27 +180,6 @@ public class ArrowDecoratedBox : TemplatedControl,
}; };
} }
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
{
base.OnAttachedToLogicalTree(e);
if (!_initialized) {
_customStyle.SetupUI();
SetupRelayProperties();
}
}
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
SetupRelayProperties();
}
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnDetachedFromVisualTree(e);
_compositeDisposable?.Dispose();
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs e) protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs e)
{ {
base.OnPropertyChanged(e); base.OnPropertyChanged(e);
@ -208,54 +196,20 @@ public class ArrowDecoratedBox : TemplatedControl,
return GetContentRect(DesiredSize).Deflate(0.5); return GetContentRect(DesiredSize).Deflate(0.5);
} }
#region IControlCustomStyle protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
// 组件的 Token 绑定属性 base.OnApplyTemplate(e);
private double _arrowSize; _customStyle.HandleTemplateApplied(e.NameScope);
}
private static readonly DirectProperty<ArrowDecoratedBox, double> ArrowSizeTokenProperty
= AvaloniaProperty.RegisterDirect<ArrowDecoratedBox, double>(nameof(_arrowSize), void IControlCustomStyle.HandleTemplateApplied(INameScope scope)
(o) => o._arrowSize,
(o, v) => o._arrowSize = v);
// 组件的 Token 绑定属性
void IControlCustomStyle.SetupUI()
{ {
_container = new Border();
_customStyle.SetupTokenBindings();
if (IsShowArrow) { if (IsShowArrow) {
BuildGeometry(true); BuildGeometry(true);
} }
LogicalChildren.Add(_container);
VisualChildren.Add(_container);
BindUtils.CreateTokenBinding(this, BackgroundProperty, GlobalResourceKey.ColorBgContainer);
_initialized = true;
}
private void SetupRelayProperties()
{
_compositeDisposable = new CompositeDisposable();
// 生命周期一样,可以不用管理
if (_container is not null) {
if (Child?.Parent is not null) {
UIStructureUtils.ClearLogicalParentRecursive(Child, null);
UIStructureUtils.ClearVisualParentRecursive(Child, null);
}
_compositeDisposable.Add(BindUtils.RelayBind(this, BackgroundSizingProperty, _container));
_compositeDisposable.Add(BindUtils.RelayBind(this, BackgroundProperty, _container));
_compositeDisposable.Add(BindUtils.RelayBind(this, CornerRadiusProperty, _container));
_compositeDisposable.Add(BindUtils.RelayBind(this, ChildProperty, _container));
_compositeDisposable.Add(BindUtils.RelayBind(this, PaddingProperty, _container));
}
}
void IControlCustomStyle.SetupTokenBindings()
{
NotifySetupTokenBindings();
} }
#region IControlCustomStyle
private (double, double) GetArrowVertexPoint() private (double, double) GetArrowVertexPoint()
{ {
@ -272,7 +226,7 @@ public class ArrowDecoratedBox : TemplatedControl,
{ {
if (e.Property == IsShowArrowProperty || if (e.Property == IsShowArrowProperty ||
e.Property == ArrowPositionProperty || e.Property == ArrowPositionProperty ||
e.Property == ArrowSizeTokenProperty || e.Property == ArrowSizeProperty ||
e.Property == VisualParentProperty) { e.Property == VisualParentProperty) {
if (e.Property == IsShowArrowProperty && VisualRoot is null) { if (e.Property == IsShowArrowProperty && VisualRoot is null) {
// 当开启的时候,但是还没有加入的渲染树,这个时候我们取不到 Token 需要在取值的时候重新生成一下 // 当开启的时候,但是还没有加入的渲染树,这个时候我们取不到 Token 需要在取值的时候重新生成一下
@ -289,40 +243,32 @@ public class ArrowDecoratedBox : TemplatedControl,
private void BuildGeometry(bool force = false) private void BuildGeometry(bool force = false)
{ {
if (_arrowGeometry is null || force) { if (_arrowGeometry is null || force) {
_arrowGeometry = CommonShapeBuilder.BuildArrow(_arrowSize, 1.5); _arrowGeometry = CommonShapeBuilder.BuildArrow(ArrowSize, 1.5);
} }
} }
protected virtual void NotifySetupTokenBindings()
{
BindUtils.CreateTokenBinding(this, MinHeightProperty, GlobalResourceKey.ControlHeight);
BindUtils.CreateTokenBinding(this, PaddingProperty, GlobalResourceKey.PaddingXS);
BindUtils.CreateTokenBinding(this, ArrowSizeTokenProperty, ArrowDecoratedBoxResourceKey.ArrowSize);
BindUtils.CreateTokenBinding(this, CornerRadiusProperty, GlobalResourceKey.BorderRadius);
}
public sealed override void Render(DrawingContext context) public sealed override void Render(DrawingContext context)
{ {
if (IsShowArrow) { if (IsShowArrow) {
var direction = GetDirection(ArrowPosition); var direction = GetDirection(ArrowPosition);
var matrix = Matrix.CreateTranslation(-_arrowSize / 2, -_arrowSize / 2); var matrix = Matrix.CreateTranslation(-ArrowSize / 2, -ArrowSize / 2);
if (direction == Direction.Right) { if (direction == Direction.Right) {
matrix *= Matrix.CreateRotation(MathUtils.Deg2Rad(90)); matrix *= Matrix.CreateRotation(MathUtils.Deg2Rad(90));
matrix *= Matrix.CreateTranslation(_arrowSize / 2, _arrowSize / 2); matrix *= Matrix.CreateTranslation(ArrowSize / 2, ArrowSize / 2);
} else if (direction == Direction.Top) { } else if (direction == Direction.Top) {
matrix *= Matrix.CreateTranslation(_arrowSize / 2, 0); matrix *= Matrix.CreateTranslation(ArrowSize / 2, 0);
} else if (direction == Direction.Left) { } else if (direction == Direction.Left) {
matrix *= Matrix.CreateRotation(MathUtils.Deg2Rad(-90)); matrix *= Matrix.CreateRotation(MathUtils.Deg2Rad(-90));
matrix *= Matrix.CreateTranslation(0, _arrowSize / 2); matrix *= Matrix.CreateTranslation(0, ArrowSize / 2);
} else { } else {
matrix *= Matrix.CreateRotation(MathUtils.Deg2Rad(180)); matrix *= Matrix.CreateRotation(MathUtils.Deg2Rad(180));
matrix *= Matrix.CreateTranslation(_arrowSize / 2, _arrowSize / 2); matrix *= Matrix.CreateTranslation(ArrowSize / 2, ArrowSize / 2);
} }
matrix *= Matrix.CreateTranslation(_arrowRect.X, _arrowRect.Y); matrix *= Matrix.CreateTranslation(_arrowRect.X, _arrowRect.Y);
_arrowGeometry!.Transform = new MatrixTransform(matrix); _arrowGeometry!.Transform = new MatrixTransform(matrix);
context.DrawGeometry(_container?.Background, null, _arrowGeometry); context.DrawGeometry(Background, null, _arrowGeometry);
} }
} }

View File

@ -1,4 +1,5 @@
using AtomUI.TokenSystem; using AtomUI.TokenSystem;
using Avalonia;
namespace AtomUI.Controls; namespace AtomUI.Controls;
@ -12,6 +13,11 @@ public class ArrowDecoratedBoxToken : AbstractControlDesignToken
/// </summary> /// </summary>
public double ArrowSize { get; set; } public double ArrowSize { get; set; }
/// <summary>
/// 默认的内边距
/// </summary>
public Thickness Padding { get; set; }
public ArrowDecoratedBoxToken() public ArrowDecoratedBoxToken()
: base(ID) : base(ID)
{ {
@ -21,5 +27,6 @@ public class ArrowDecoratedBoxToken : AbstractControlDesignToken
{ {
base.CalculateFromAlias(); base.CalculateFromAlias();
ArrowSize = _globalToken.SeedToken.SizePopupArrow / 1.3; ArrowSize = _globalToken.SeedToken.SizePopupArrow / 1.3;
Padding = new Thickness(_globalToken.PaddingXS);
} }
} }

View File

@ -158,7 +158,7 @@ public class Flyout : PopupFlyoutBase
{ {
var presenter = new FlyoutPresenter var presenter = new FlyoutPresenter
{ {
[!Border.ChildProperty] = this[!ContentProperty] [!FlyoutPresenter.ChildProperty] = this[!ContentProperty]
}; };
BindUtils.RelayBind(this, IsShowArrowEffectiveProperty, presenter, IsShowArrowProperty); BindUtils.RelayBind(this, IsShowArrowEffectiveProperty, presenter, IsShowArrowProperty);
SetupArrowPosition(AtomPopup, presenter); SetupArrowPosition(AtomPopup, presenter);

View File

@ -4,7 +4,9 @@ using Avalonia.LogicalTree;
namespace AtomUI.Controls; namespace AtomUI.Controls;
public class FlyoutPresenter : ArrowDecoratedBox public class FlyoutPresenter : ArrowDecoratedBox
{ {
// 我们在这里并没有增加任何元素或者样式
protected override Type StyleKeyOverride => typeof(ArrowDecoratedBox);
protected override void OnKeyDown(KeyEventArgs e) protected override void OnKeyDown(KeyEventArgs e)
{ {
if (e.Key == Key.Escape) if (e.Key == Key.Escape)

View File

@ -0,0 +1,20 @@
using AtomUI.Styling;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
namespace AtomUI.Controls;
[ControlThemeProvider]
public class FlyoutPresenterTheme : ControlTheme
{
public FlyoutPresenterTheme() : base(typeof(FlyoutPresenter)) {}
protected override IControlTemplate? BuildControlTemplate()
{
return new FuncControlTemplate<FlyoutPresenter>(((presenter, scope) =>
{
Console.WriteLine("xxxxxxxxxxxxxx");
return new Panel();
}));
}
}

View File

@ -1,11 +0,0 @@
using Avalonia.Controls;
namespace AtomUI.Controls;
public class InfoFlyout : PopupFlyoutBase
{
protected override Control CreatePresenter()
{
return default!;
}
}

View File

@ -18,6 +18,7 @@ namespace AtomUI.Styling
public static class ArrowDecoratedBoxResourceKey public static class ArrowDecoratedBoxResourceKey
{ {
public static readonly TokenResourceKey ArrowSize = new TokenResourceKey("ArrowDecoratedBox.ArrowSize"); public static readonly TokenResourceKey ArrowSize = new TokenResourceKey("ArrowDecoratedBox.ArrowSize");
public static readonly TokenResourceKey Padding = new TokenResourceKey("ArrowDecoratedBox.Padding");
} }
public static class BadgeResourceKey public static class BadgeResourceKey

View File

@ -1,5 +1,6 @@
using AtomUI.TokenSystem; using AtomUI.TokenSystem;
using Avalonia; using Avalonia;
using Avalonia.Data;
using Avalonia.Markup.Xaml.MarkupExtensions; using Avalonia.Markup.Xaml.MarkupExtensions;
using Avalonia.Styling; using Avalonia.Styling;