完成 tooltip 改造

This commit is contained in:
polarboy 2024-07-17 17:49:12 +08:00
parent 949f3a3bf2
commit 02a74a855e
5 changed files with 88 additions and 59 deletions

View File

@ -50,7 +50,7 @@ public static class BindUtils
public static IDisposable CreateTokenBinding(AvaloniaObject target,
AvaloniaProperty targetProperty,
string resourceKey)
object resourceKey)
{
return target.Bind(targetProperty, new DynamicResourceExtension(resourceKey));
}

View File

@ -1,5 +1,4 @@
using AtomUI.Data;
using AtomUI.Icon;
using AtomUI.Icon;
using AtomUI.Styling;
using AtomUI.Utils;
using Avalonia;

View File

@ -24,7 +24,7 @@ namespace AtomUI.Controls;
using AvaloniaWin = Avalonia.Controls.Window;
[PseudoClasses(StdPseudoClass.Open)]
public partial class ToolTip : StyledControl,
public partial class ToolTip : TemplatedControl,
IShadowMaskInfoProvider,
IControlCustomStyle
{
@ -49,9 +49,8 @@ public partial class ToolTip : StyledControl,
typeof(ThemeVariant).GetFieldInfoOrThrow("RequestedThemeVariantProperty",
BindingFlags.Static | BindingFlags.NonPublic);
RequestedThemeVariantProperty = (StyledProperty<ThemeVariant?>)requestedThemeVariantProperty.GetValue(null)!;
AffectsRender<ToolTip>(DefaultBgTokenProperty,
ForegroundProperty,
BackgroundProperty);
AffectsRender<ToolTip>(ForegroundProperty,
BackgroundProperty);
AffectsArrange<ToolTip>(FlipPlacementProperty);
}
@ -468,7 +467,7 @@ public partial class ToolTip : StyledControl,
var marginToAnchor = GetMarginToAnchor(control);
if (double.IsNaN(marginToAnchor)) {
marginToAnchor = _marginXXS / 2;
marginToAnchor = _marginXXSToken / 2;
}
var placement = GetPlacement(control);
@ -542,7 +541,7 @@ public partial class ToolTip : StyledControl,
var topLevel = TopLevel.GetTopLevel(placementTarget);
var motionActor =
new PopupMotionActor(_shadows, positionInfo.Offset, positionInfo.Scaling, contentControl, motion);
new PopupMotionActor(_shadowsToken, positionInfo.Offset, positionInfo.Scaling, contentControl, motion);
motionActor.DispatchInSceneLayer = true;
motionActor.SceneParent = topLevel;
motionActor.Completed += (sender, args) =>
@ -607,7 +606,7 @@ public partial class ToolTip : StyledControl,
UIStructureUtils.SetVisualParent(popup.Child, null);
UIStructureUtils.SetVisualParent(popup.Child, null);
var motionActor = new PopupMotionActor(_shadows, _popupPositionInfo.Offset, _popupPositionInfo.Scaling,
var motionActor = new PopupMotionActor(_shadowsToken, _popupPositionInfo.Offset, _popupPositionInfo.Scaling,
popup.Child, motion);
motionActor.DispatchInSceneLayer = true;
motionActor.SceneParent = placementToplevel;
@ -669,43 +668,34 @@ public partial class ToolTip : StyledControl,
}
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
_customStyle.HandleTemplateApplied(e.NameScope);
}
void IControlCustomStyle.HandleTemplateApplied(INameScope scope)
{
_arrowDecoratedBox = scope.Find<ArrowDecoratedBox>(ToolTipTheme.ToolTipContainerPart);
_customStyle.ApplyFixedStyleConfig();
}
#region IControlCustomStyle
void IControlCustomStyle.SetupUi()
{
Background = new SolidColorBrush(Colors.Transparent);
_arrowDecoratedBox = new ArrowDecoratedBox();
if (Content is string text) {
_arrowDecoratedBox.Child = new TextBlock
{
Text = text,
VerticalAlignment = VerticalAlignment.Center,
HorizontalAlignment = HorizontalAlignment.Center,
TextWrapping = TextWrapping.Wrap,
};
} else if (Content is Control control) {
_arrowDecoratedBox.Child = control;
}
((ISetLogicalParent)_arrowDecoratedBox).SetParent(this);
VisualChildren.Add(_arrowDecoratedBox);
_customStyle.ApplyFixedStyleConfig();
BindUtils.CreateTokenBinding(this, ThemeProperty, typeof(ToolTip));
// 手动提前应用模板
ApplyStyling();
ApplyTemplate();
}
void IControlCustomStyle.ApplyFixedStyleConfig()
{
if (_arrowDecoratedBox is not null) {
_controlTokenBinder.AddControlBinding(_arrowDecoratedBox, FontSizeProperty, GlobalResourceKey.FontSize);
_controlTokenBinder.AddControlBinding(_arrowDecoratedBox, MaxWidthProperty, ToolTipResourceKey.ToolTipMaxWidth);
_controlTokenBinder.AddControlBinding(_arrowDecoratedBox, BackgroundProperty, ToolTipResourceKey.ToolTipBackground);
_controlTokenBinder.AddControlBinding(_arrowDecoratedBox, ForegroundProperty, ToolTipResourceKey.ToolTipColor);
_controlTokenBinder.AddControlBinding(_arrowDecoratedBox, MinHeightProperty, GlobalResourceKey.ControlHeight);
_controlTokenBinder.AddControlBinding(_arrowDecoratedBox, PaddingProperty, ToolTipResourceKey.ToolTipPadding);
_controlTokenBinder.AddControlBinding(MarginXXSTokenProperty, GlobalResourceKey.MarginXXS);
_controlTokenBinder.AddControlBinding(MotionDurationTokenProperty, GlobalResourceKey.MotionDurationMid);
_controlTokenBinder.AddControlBinding(ShadowsTokenProperty, GlobalResourceKey.BoxShadowsSecondary);
_controlTokenBinder.AddControlBinding(_arrowDecoratedBox, ArrowDecoratedBox.CornerRadiusProperty, ToolTipResourceKey.BorderRadiusOuter);
// TODO 生命周期一样还需要管理起来吗?
BindUtils.RelayBind(this, IsShowArrowEffectiveProperty, _arrowDecoratedBox, ArrowDecoratedBox.IsShowArrowProperty);
}
}

View File

@ -114,39 +114,26 @@ public partial class ToolTip
// 私有属性
private static StyledProperty<ThemeVariant?> RequestedThemeVariantProperty;
private static readonly StyledProperty<bool> IsShowArrowEffectiveProperty =
internal static readonly StyledProperty<bool> IsShowArrowEffectiveProperty =
ArrowDecoratedBox.IsShowArrowProperty.AddOwner<ToolTip>();
/// <summary>
/// 是否实际显示箭头
/// </summary>
public bool IsShowArrowEffective
internal bool IsShowArrowEffective
{
get => GetValue(IsShowArrowEffectiveProperty);
set => SetValue(IsShowArrowEffectiveProperty, value);
}
// 组件的 Token 绑定属性
private IBrush? _defaultBackground;
private static readonly DirectProperty<ToolTip, IBrush?> DefaultBgTokenProperty
= AvaloniaProperty.RegisterDirect<ToolTip, IBrush?>(nameof(_defaultBackground),
(o) => o._defaultBackground,
(o, v) => o._defaultBackground = v);
private double _toolTipArrowSize;
private static readonly DirectProperty<ToolTip, double> ToolTipArrowSizeTokenProperty
= AvaloniaProperty.RegisterDirect<ToolTip, double>(nameof(_toolTipArrowSize),
(o) => o._toolTipArrowSize,
(o, v) => o._toolTipArrowSize = v);
private double _marginXXS;
private double _marginXXSToken;
private static readonly DirectProperty<ToolTip, double> MarginXXSTokenProperty
= AvaloniaProperty.RegisterDirect<ToolTip, double>(nameof(_marginXXS),
(o) => o._marginXXS,
(o, v) => o._marginXXS = v);
= AvaloniaProperty.RegisterDirect<ToolTip, double>(nameof(_marginXXSToken),
(o) => o._marginXXSToken,
(o, v) => o._marginXXSToken = v);
private TimeSpan _motionDuration;
@ -156,12 +143,12 @@ public partial class ToolTip
(o, v) => o._motionDuration = v);
// 暂时不支持自定义
private BoxShadows _shadows;
private BoxShadows _shadowsToken;
private static readonly DirectProperty<ToolTip, BoxShadows> ShadowsTokenProperty
= AvaloniaProperty.RegisterDirect<ToolTip, BoxShadows>(nameof(_shadows),
(o) => o._shadows,
(o, v) => o._shadows = v);
= AvaloniaProperty.RegisterDirect<ToolTip, BoxShadows>(nameof(_shadowsToken),
(o) => o._shadowsToken,
(o, v) => o._shadowsToken = v);
// 组件的 Token 绑定属性
internal static readonly DirectProperty<ToolTip, PlacementMode?> FlipPlacementProperty =

View File

@ -0,0 +1,53 @@
using AtomUI.Styling;
using AtomUI.Utils;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using Avalonia.Layout;
using Avalonia.Media;
namespace AtomUI.Controls;
[ControlThemeProvider]
public class ToolTipTheme : ControlTheme
{
public const string ToolTipContainerPart = "PART_ToolTipContainer";
public ToolTipTheme()
: base(typeof(ToolTip))
{
}
protected override IControlTemplate? BuildControlTemplate()
{
return new FuncControlTemplate<ToolTip>((tip, scope) =>
{
var arrowDecoratedBox = new ArrowDecoratedBox()
{
Name = ToolTipContainerPart,
};
if (tip.Content is string text) {
arrowDecoratedBox.Child = new TextBlock
{
Text = text,
VerticalAlignment = VerticalAlignment.Center,
HorizontalAlignment = HorizontalAlignment.Center,
TextWrapping = TextWrapping.Wrap,
};
} else if (tip.Content is Control control) {
arrowDecoratedBox.Child = control;
}
BindUtils.CreateTokenBinding(arrowDecoratedBox, ArrowDecoratedBox.FontSizeProperty, GlobalResourceKey.FontSize);
BindUtils.CreateTokenBinding(arrowDecoratedBox, ArrowDecoratedBox.MaxWidthProperty, ToolTipResourceKey.ToolTipMaxWidth);
BindUtils.CreateTokenBinding(arrowDecoratedBox, ArrowDecoratedBox.BackgroundProperty, ToolTipResourceKey.ToolTipBackground);
BindUtils.CreateTokenBinding(arrowDecoratedBox, ArrowDecoratedBox.ForegroundProperty, ToolTipResourceKey.ToolTipColor);
BindUtils.CreateTokenBinding(arrowDecoratedBox, ArrowDecoratedBox.MinHeightProperty, GlobalResourceKey.ControlHeight);
BindUtils.CreateTokenBinding(arrowDecoratedBox, ArrowDecoratedBox.PaddingProperty, ToolTipResourceKey.ToolTipPadding);
BindUtils.CreateTokenBinding(arrowDecoratedBox, ArrowDecoratedBox.CornerRadiusProperty, ToolTipResourceKey.BorderRadiusOuter);
CreateTemplateParentBinding(arrowDecoratedBox, ArrowDecoratedBox.IsShowArrowProperty, ToolTip.IsShowArrowEffectiveProperty);
arrowDecoratedBox.RegisterInNameScope(scope);
return arrowDecoratedBox;
});
}
}