Refactor TextBlock

This commit is contained in:
chinboy
2025-02-12 10:41:14 +08:00
parent f0f3f6ee29
commit 88d400a008
5 changed files with 57 additions and 112 deletions
@@ -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;
+4 -82
View File
@@ -105,10 +105,10 @@ public class Tag : TemplatedControl
#region 内部属性定义
internal static readonly StyledProperty<double> TagTextPaddingInlineProperty
= AvaloniaProperty.Register<Tag, double>(nameof(TagTextPaddingInline));
internal static readonly StyledProperty<Thickness> TagTextPaddingInlineProperty
= AvaloniaProperty.Register<Tag, Thickness>(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<Canvas>(TagTheme.MainContainerPart);
_closeButton = scope.Find<IconButton>(TagTheme.CloseButtonPart);
_textBlock = scope.Find<TextBlock>(TagTheme.TagTextLabelPart);
_iconContentPresenter = scope.Find<ContentPresenter>(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);
}
}
+41 -18
View File
@@ -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>((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;
});
}
}
+3 -3
View File
@@ -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);
}
}
+8 -9
View File
@@ -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));
}
}