From 88d400a0086a8af67a08c4012e56950caa3198e0 Mon Sep 17 00:00:00 2001 From: chinboy Date: Wed, 12 Feb 2025 10:41:14 +0800 Subject: [PATCH] Refactor TextBlock --- .../MarqueeLabel/MarqueeLabel.cs | 1 + src/AtomUI.Controls/Tag/Tag.cs | 86 +------------------ src/AtomUI.Controls/Tag/TagTheme.cs | 59 +++++++++---- src/AtomUI.Controls/Tag/TagToken.cs | 6 +- src/AtomUI.Controls/TextBlock.cs | 17 ++-- 5 files changed, 57 insertions(+), 112 deletions(-) diff --git a/src/AtomUI.Controls/MarqueeLabel/MarqueeLabel.cs b/src/AtomUI.Controls/MarqueeLabel/MarqueeLabel.cs index e8c5a2117..615a90d86 100644 --- a/src/AtomUI.Controls/MarqueeLabel/MarqueeLabel.cs +++ b/src/AtomUI.Controls/MarqueeLabel/MarqueeLabel.cs @@ -3,6 +3,7 @@ using AtomUI.Theme.Styling; using AtomUI.Utils; using Avalonia; using Avalonia.Animation; +using Avalonia.Controls; using Avalonia.Layout; using Avalonia.Media; using Avalonia.Styling; diff --git a/src/AtomUI.Controls/Tag/Tag.cs b/src/AtomUI.Controls/Tag/Tag.cs index 58c03bc87..82c051dd2 100644 --- a/src/AtomUI.Controls/Tag/Tag.cs +++ b/src/AtomUI.Controls/Tag/Tag.cs @@ -105,10 +105,10 @@ public class Tag : TemplatedControl #region 内部属性定义 - internal static readonly StyledProperty TagTextPaddingInlineProperty - = AvaloniaProperty.Register(nameof(TagTextPaddingInline)); + internal static readonly StyledProperty TagTextPaddingInlineProperty + = AvaloniaProperty.Register(nameof(TagTextPaddingInline)); - internal double TagTextPaddingInline + internal Thickness TagTextPaddingInline { get => GetValue(TagTextPaddingInlineProperty); set => SetValue(TagTextPaddingInlineProperty, value); @@ -153,7 +153,6 @@ public class Tag : TemplatedControl private void HandleTemplateApplied(INameScope scope) { - _layoutPanel = scope.Find(TagTheme.MainContainerPart); _closeButton = scope.Find(TagTheme.CloseButtonPart); _textBlock = scope.Find(TagTheme.TagTextLabelPart); _iconContentPresenter = scope.Find(TagTheme.IconPart); @@ -167,72 +166,7 @@ public class Tag : TemplatedControl SetupTagIcon(); SetupTokenBindings(); } - - protected override Size MeasureOverride(Size availableSize) - { - base.MeasureOverride(availableSize); - var targetWidth = 0d; - var targetHeight = 0d; - if (_layoutPanel is not null) - { - foreach (var child in _layoutPanel.Children) - { - targetWidth += child.DesiredSize.Width; - targetHeight = Math.Max(targetHeight, child.DesiredSize.Height); - } - } - - if (Icon is not null) - { - targetWidth += TagTextPaddingInline; - } - - if (IsClosable && _closeButton is not null) - { - targetWidth += TagTextPaddingInline; - } - - targetWidth += Padding.Left + Padding.Right; - return new Size(targetWidth, targetHeight); - } - - protected override Size ArrangeOverride(Size finalSize) - { - if (_closeButton is not null) - { - var offsetX = finalSize.Width - Padding.Right - _closeButton.DesiredSize.Width; - var offsetY = (finalSize.Height - _closeButton.DesiredSize.Height) / 2; - Canvas.SetLeft(_closeButton, offsetX); - Canvas.SetTop(_closeButton, offsetY); - } - - // icon - if (_iconContentPresenter is not null) - { - var offsetX = Padding.Left; - var offsetY = (finalSize.Height - _iconContentPresenter.DesiredSize.Height) / 2; - Canvas.SetLeft(_iconContentPresenter, offsetX); - Canvas.SetTop(_iconContentPresenter, offsetY); - } - - // 文字 - if (_textBlock is not null) - { - var offsetX = Padding.Left; - if (Icon is not null) - { - offsetX += Icon.DesiredSize.Width + TagTextPaddingInline; - } - - // 这个时候已经算好了 - var offsetY = (finalSize.Height - _textBlock.Height) / 2; - Canvas.SetLeft(_textBlock, offsetX); - Canvas.SetTop(_textBlock, offsetY); - } - - return base.ArrangeOverride(finalSize); - } - + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs e) { base.OnPropertyChanged(e); @@ -424,16 +358,4 @@ public class Tag : TemplatedControl } } } - - public override void Render(DrawingContext context) - { - _borderRenderHelper.Render(context, - Bounds.Size, - BorderThickness, - CornerRadius, - BackgroundSizing, - Background, - BorderBrush, - default); - } } \ No newline at end of file diff --git a/src/AtomUI.Controls/Tag/TagTheme.cs b/src/AtomUI.Controls/Tag/TagTheme.cs index 402b2866b..b4599fa4e 100644 --- a/src/AtomUI.Controls/Tag/TagTheme.cs +++ b/src/AtomUI.Controls/Tag/TagTheme.cs @@ -13,7 +13,8 @@ namespace AtomUI.Controls; [ControlThemeProvider] internal class TagTheme : BaseControlTheme { - public const string MainContainerPart = "PART_MainContainer"; + public const string ElementsLayoutPart = "PART_ElementsLayout"; + public const string FramePart = "PART_Frame"; public const string IconPart = "PART_Icon"; public const string CloseButtonPart = "PART_CloseButton"; public const string TagTextLabelPart = "PART_TagTextLabel"; @@ -25,12 +26,13 @@ internal class TagTheme : BaseControlTheme protected override void BuildStyles() { - this.Add(TemplatedControl.BackgroundProperty, TagTokenKey.DefaultBg); - this.Add(TemplatedControl.ForegroundProperty, TagTokenKey.DefaultColor); - this.Add(TemplatedControl.FontSizeProperty, TagTokenKey.TagFontSize); - this.Add(TemplatedControl.PaddingProperty, TagTokenKey.TagPadding); - this.Add(TemplatedControl.BorderBrushProperty, SharedTokenKey.ColorBorder); - this.Add(TemplatedControl.CornerRadiusProperty, SharedTokenKey.BorderRadiusSM); + this.Add(Tag.BackgroundProperty, TagTokenKey.DefaultBg); + this.Add(Tag.ForegroundProperty, TagTokenKey.DefaultColor); + this.Add(Tag.FontSizeProperty, TagTokenKey.TagFontSize); + this.Add(Tag.PaddingProperty, TagTokenKey.TagPadding); + this.Add(Tag.BorderBrushProperty, SharedTokenKey.ColorBorder); + this.Add(Tag.CornerRadiusProperty, SharedTokenKey.BorderRadiusSM); + this.Add(Tag.HeightProperty, TagTokenKey.TagLineHeight); this.Add(Tag.TagTextPaddingInlineProperty, TagTokenKey.TagTextPaddingInline); } @@ -38,49 +40,70 @@ internal class TagTheme : BaseControlTheme { return new FuncControlTemplate((tag, scope) => { - var layout = new Canvas + var rootLayout = new Panel(); + + var frameDecorator = new Border() { - Name = MainContainerPart + Name = FramePart }; + CreateTemplateParentBinding(frameDecorator, Border.BackgroundProperty, Tag.BackgroundProperty); + CreateTemplateParentBinding(frameDecorator, Border.BorderBrushProperty, Tag.BorderBrushProperty); + CreateTemplateParentBinding(frameDecorator, Border.CornerRadiusProperty, Tag.CornerRadiusProperty); + CreateTemplateParentBinding(frameDecorator, Border.BorderThicknessProperty, Tag.BorderThicknessProperty); - layout.RegisterInNameScope(scope); + rootLayout.Children.Add(frameDecorator); + + var elementsLayout = new Grid + { + Name = ElementsLayoutPart, + ColumnDefinitions = + { + new ColumnDefinition(GridLength.Auto), + new ColumnDefinition(GridLength.Star), + new ColumnDefinition(GridLength.Auto) + } + }; + CreateTemplateParentBinding(elementsLayout, Grid.MarginProperty, Tag.PaddingProperty); + elementsLayout.RegisterInNameScope(scope); + rootLayout.Children.Add(elementsLayout); var iconContentPresenter = new ContentPresenter() { Name = IconPart }; + Grid.SetColumn(iconContentPresenter, 0); iconContentPresenter.RegisterInNameScope(scope); CreateTemplateParentBinding(iconContentPresenter, ContentPresenter.ContentProperty, Tag.IconProperty); - layout.Children.Add(iconContentPresenter); + elementsLayout.Children.Add(iconContentPresenter); var textBlock = new TextBlock { Name = TagTextLabelPart, - VerticalAlignment = VerticalAlignment.Center + VerticalAlignment = VerticalAlignment.Center, }; + Grid.SetColumn(textBlock, 1); textBlock.RegisterInNameScope(scope); CreateTemplateParentBinding(textBlock, TextBlock.TextProperty, Tag.TagTextProperty); - layout.Children.Add(textBlock); + CreateTemplateParentBinding(textBlock, TextBlock.PaddingProperty, Tag.TagTextPaddingInlineProperty); + elementsLayout.Children.Add(textBlock); var closeBtn = new IconButton { Name = CloseButtonPart }; closeBtn.RegisterInNameScope(scope); - + Grid.SetColumn(closeBtn, 2); TokenResourceBinder.CreateTokenBinding(closeBtn, IconButton.IconWidthProperty, SharedTokenKey.IconSizeXS); TokenResourceBinder.CreateTokenBinding(closeBtn, IconButton.IconHeightProperty, SharedTokenKey.IconSizeXS); - TokenResourceBinder.CreateTokenBinding(textBlock, Layoutable.HeightProperty, - TagTokenKey.TagLineHeight); CreateTemplateParentBinding(closeBtn, Visual.IsVisibleProperty, Tag.IsClosableProperty); CreateTemplateParentBinding(closeBtn, IconButton.IconProperty, Tag.CloseIconProperty); - layout.Children.Add(closeBtn); + elementsLayout.Children.Add(closeBtn); - return layout; + return rootLayout; }); } } \ No newline at end of file diff --git a/src/AtomUI.Controls/Tag/TagToken.cs b/src/AtomUI.Controls/Tag/TagToken.cs index 891015ecf..66d7de28a 100644 --- a/src/AtomUI.Controls/Tag/TagToken.cs +++ b/src/AtomUI.Controls/Tag/TagToken.cs @@ -25,7 +25,7 @@ internal class TagToken : AbstractControlDesignToken public double TagIconSize { get; set; } public double TagCloseIconSize { get; set; } public Thickness TagPadding { get; set; } - public double TagTextPaddingInline { get; set; } + public Thickness TagTextPaddingInline { get; set; } public Color TagBorderlessBg { get; set; } public TagToken() @@ -40,11 +40,11 @@ internal class TagToken : AbstractControlDesignToken TagLineHeight = SharedToken.LineHeightSM * TagFontSize; TagCloseIconSize = SharedToken.IconSizeXS; TagIconSize = SharedToken.FontSizeIcon; - TagPadding = new Thickness(8, 0); // Fixed padding. + TagPadding = new Thickness(SharedToken.SizeXS, 0); // TODO 这个地方需要看看 DefaultBg = ColorUtils.OnBackground(SharedToken.ColorFillQuaternary, SharedToken.ColorBgContainer); TagBorderlessBg = DefaultBg; DefaultColor = SharedToken.ColorText; - TagTextPaddingInline = SharedToken.PaddingXXS; + TagTextPaddingInline = new Thickness(SharedToken.PaddingXXS, 0); } } \ No newline at end of file diff --git a/src/AtomUI.Controls/TextBlock.cs b/src/AtomUI.Controls/TextBlock.cs index 934857b1b..c695f8f25 100644 --- a/src/AtomUI.Controls/TextBlock.cs +++ b/src/AtomUI.Controls/TextBlock.cs @@ -58,29 +58,28 @@ public class TextBlock : AvaloniaTextBlock protected override void RenderTextLayout(DrawingContext context, Point origin) { var textHeight = TextLayout.Height; - var top = origin.Y; - var left = TextLayout.OverhangLeading; + var left = origin.X; + var top = origin.Y; if (TextLayout.TextLines.Count == 1) { + if (Bounds.Height >= textHeight) { + var scale = LayoutHelper.GetLayoutScale(this); + var padding = LayoutHelper.RoundLayoutThickness(Padding, scale, scale); switch (VerticalAlignment) { case VerticalAlignment.Center: - top += _textMetrics.Descent / 2; - break; - - case VerticalAlignment.Bottom: - top += Bounds.Height - textHeight; + top = (DesiredSize.Height - _textMetrics.LineHeight - padding.Top - padding.Bottom) / 2 - _textMetrics.Descent; break; } } - + if (HorizontalAlignment == HorizontalAlignment.Center) { left += (TextLayout.OverhangLeading + TextLayout.OverhangTrailing) / 2; } } - TextLayout.Draw(context, origin + new Point(left, top)); + TextLayout.Draw(context, new Point(left, top)); } } \ No newline at end of file