完成搜索类型的输入框

完成搜索类型的输入框
This commit is contained in:
polarboy 2024-08-07 19:50:41 +08:00
parent 2d33d56823
commit fed4c18c15
6 changed files with 230 additions and 8 deletions

View File

@ -104,5 +104,33 @@
</StackPanel>
</showcase:ShowCaseItem>
<showcase:ShowCaseItem
Title="Search box"
Description="Example of creating a search box by grouping a standard input with a search button.">
<StackPanel Orientation="Vertical" Spacing="10" Margin="0, 0, 20, 0">
<atom:SearchEdit Watermark="input search text" Width="400" HorizontalAlignment="Left"/>
<atom:SearchEdit Watermark="input search text" Width="400" HorizontalAlignment="Left" SearchButtonText="Search"/>
<atom:SearchEdit Watermark="input search text" Width="400" HorizontalAlignment="Left" SearchButtonStyle="Primary" SearchButtonText="Search"/>
<atom:SearchEdit Watermark="input search text" Width="400" HorizontalAlignment="Left" SearchButtonStyle="Primary" SearchButtonText="Search"/>
<atom:SearchEdit Watermark="input search text"
Width="400"
HorizontalAlignment="Left"
SearchButtonStyle="Primary"
SearchButtonText="Search"
IsEnableClearButton="True"
SizeType="Large"/>
<atom:SearchEdit Watermark="input search text"
Width="400"
HorizontalAlignment="Left"
SearchButtonStyle="Primary"
SearchButtonText="搜索一下"
InnerRightContent="{atom:IconProvider Kind=AudioOutlined, NormalFilledColor=#1677ff, Width=16, Height=16}"
IsEnableClearButton="True"
SizeType="Large"/>
</StackPanel>
</showcase:ShowCaseItem>
</showcase:ShowCasePanel>
</UserControl>

View File

@ -1,4 +1,5 @@
using AtomUI.Controls.Utils;
using AtomUI.Data;
using AtomUI.Icon;
using AtomUI.Media;
using AtomUI.Theme.Data;
@ -62,6 +63,9 @@ public class Button : AvaloniaButton, ISizeTypeAware, IControlCustomStyle, IWave
public static readonly StyledProperty<string?> TextProperty
= AvaloniaProperty.Register<Button, string?>(nameof(Text));
public static readonly StyledProperty<bool> IsIconVisibleProperty
= AvaloniaProperty.Register<Button, bool>(nameof (IsIconVisible), true);
public ButtonType ButtonType
{
@ -104,6 +108,12 @@ public class Button : AvaloniaButton, ISizeTypeAware, IControlCustomStyle, IWave
get => GetValue(TextProperty);
set => SetValue(TextProperty, value);
}
public bool IsIconVisible
{
get => GetValue(IsIconVisibleProperty);
set => SetValue(IsIconVisibleProperty, value);
}
#endregion
@ -347,6 +357,7 @@ public class Button : AvaloniaButton, ISizeTypeAware, IControlCustomStyle, IWave
if (Icon is not null) {
if (_stackPanel is not null) {
UIStructureUtils.SetTemplateParent(Icon, this);
BindUtils.RelayBind(this, IsIconVisibleProperty, Icon, PathIcon.IsVisibleProperty);
_stackPanel.Children.Insert(0, Icon);
}
}

View File

@ -29,6 +29,7 @@ public class LineEdit : TextBox
{
public const string ErrorPC = ":error";
public const string WarningPC = ":warning";
#region
public static readonly StyledProperty<object?> LeftAddOnProperty =
@ -172,9 +173,9 @@ public class LineEdit : TextBox
#endregion
private ContentPresenter? _leftAddOnPresenter;
private ContentPresenter? _rightAddOnPresenter;
private Border? _lineEditKernelDecorator;
protected Control? _leftAddOnPresenter;
protected Control? _rightAddOnPresenter;
protected Border? _lineEditKernelDecorator;
static LineEdit()
@ -188,8 +189,8 @@ public class LineEdit : TextBox
base.OnApplyTemplate(e);
TokenResourceBinder.CreateGlobalResourceBinding(this, BorderThicknessProperty, GlobalResourceKey.BorderThickness,
BindingPriority.Template, new RenderScaleAwareThicknessConfigure(this));
_leftAddOnPresenter = e.NameScope.Find<ContentPresenter>(LineEditTheme.LeftAddOnPart);
_rightAddOnPresenter = e.NameScope.Find<ContentPresenter>(LineEditTheme.RightAddOnPart);
_leftAddOnPresenter = e.NameScope.Find<Control>(LineEditTheme.LeftAddOnPart);
_rightAddOnPresenter = e.NameScope.Find<Control>(LineEditTheme.RightAddOnPart);
_lineEditKernelDecorator = e.NameScope.Find<Border>(LineEditTheme.LineEditKernelDecoratorPart);
SetupEditKernelCornerRadius();
SetupEffectiveShowClearButton();
@ -221,7 +222,9 @@ public class LineEdit : TextBox
}
if (change.Property == InnerLeftContentProperty ||
change.Property == InnerRightContentProperty) {
change.Property == InnerRightContentProperty ||
change.Property == LeftAddOnProperty ||
change.Property == RightAddOnProperty) {
if (change.OldValue is Control oldControl) {
UIStructureUtils.SetTemplateParent(oldControl, null);
}
@ -255,6 +258,13 @@ public class LineEdit : TextBox
LeftAddOnBorderThickness = new Thickness(top: topThickness, right:0, bottom:bottomThickness, left: leftThickness);
RightAddOnBorderThickness = new Thickness(top: topThickness, right:rightThickness, bottom:bottomThickness, left: 0);
NotifyAddOnBorderInfoCalculated();
}
protected virtual void NotifyAddOnBorderInfoCalculated()
{
}
private void SetupEditKernelCornerRadius()

View File

@ -32,6 +32,10 @@ internal class LineEditTheme : BaseControlTheme
public const string LineEditKernelPart = "PART_LineEditKernel";
public const string LineEditKernelDecoratorPart = "PART_LineEditKernelDecorator";
public const int NormalZIndex = 1000;
public const int ActivatedZIndex = 2000;
public LineEditTheme(Type targetType) : base(targetType) { }
public LineEditTheme() : base(typeof(LineEdit)) { }
protected override IControlTemplate? BuildControlTemplate()
@ -108,7 +112,6 @@ internal class LineEditTheme : BaseControlTheme
var kernelLayout = new LineEditKernel()
{
Name = LineEditKernelPart,
ZIndex = 1000,
Cursor = new Cursor(StandardCursorType.Ibeam)
};
@ -356,6 +359,10 @@ internal class LineEditTheme : BaseControlTheme
var commonStyle = new Style(selector => selector.Nesting());
commonStyle.Add(LineEdit.ForegroundProperty, GlobalResourceKey.ColorText);
var decoratorStyle = new Style(selector => selector.Nesting().Template().Name(LineEditKernelDecoratorPart));
decoratorStyle.Add(Border.ZIndexProperty, NormalZIndex);
commonStyle.Add(decoratorStyle);
// 输入框左右小组件的 margin 设置
var leftInnerContentStyle = new Style(selector => selector.Nesting().Template().Name(LeftInnerContentPart));
leftInnerContentStyle.Add(ContentPresenter.PaddingProperty, LineEditResourceKey.LeftInnerAddOnMargin);
@ -397,6 +404,15 @@ internal class LineEditTheme : BaseControlTheme
addOnStyle.Add(ContentPresenter.PaddingProperty, LineEditResourceKey.PaddingLG);
largeStyle.Add(addOnStyle);
}
{
// 左右 AddOn icon 的大小
var addOnContentIconStyle = new Style(selector => Selectors.Or(selector.Nesting().Template().Name(LeftAddOnPart).Descendant().OfType<PathIcon>(),
selector.Nesting().Template().Name(RightAddOnPart).Descendant().OfType<PathIcon>()));
addOnContentIconStyle.Add(PathIcon.WidthProperty, GlobalResourceKey.IconSizeLG);
addOnContentIconStyle.Add(PathIcon.HeightProperty, GlobalResourceKey.IconSizeLG);
largeStyle.Add(addOnContentIconStyle);
}
largeStyle.Add(LineEdit.FontSizeProperty, LineEditResourceKey.InputFontSizeLG);
largeStyle.Add(LineEdit.LineHeightProperty, GlobalResourceKey.FontHeightLG);
@ -418,6 +434,15 @@ internal class LineEditTheme : BaseControlTheme
addOnStyle.Add(ContentPresenter.PaddingProperty, LineEditResourceKey.Padding);
middleStyle.Add(addOnStyle);
}
{
// 左右 AddOn icon 的大小
var addOnContentIconStyle = new Style(selector => Selectors.Or(selector.Nesting().Template().Name(LeftAddOnPart).Descendant().OfType<PathIcon>(),
selector.Nesting().Template().Name(RightAddOnPart).Descendant().OfType<PathIcon>()));
addOnContentIconStyle.Add(PathIcon.WidthProperty, GlobalResourceKey.IconSize);
addOnContentIconStyle.Add(PathIcon.HeightProperty, GlobalResourceKey.IconSize);
middleStyle.Add(addOnContentIconStyle);
}
middleStyle.Add(LineEdit.FontSizeProperty, LineEditResourceKey.InputFontSize);
middleStyle.Add(LineEdit.LineHeightProperty, GlobalResourceKey.FontHeight);
@ -439,6 +464,16 @@ internal class LineEditTheme : BaseControlTheme
addOnStyle.Add(ContentPresenter.PaddingProperty, LineEditResourceKey.PaddingSM);
smallStyle.Add(addOnStyle);
}
{
// 左右 AddOn icon 的大小
var addOnContentIconStyle = new Style(selector => Selectors.Or(selector.Nesting().Template().Name(LeftAddOnPart).Descendant().OfType<PathIcon>(),
selector.Nesting().Template().Name(RightAddOnPart).Descendant().OfType<PathIcon>()));
addOnContentIconStyle.Add(PathIcon.WidthProperty, GlobalResourceKey.IconSizeSM);
addOnContentIconStyle.Add(PathIcon.HeightProperty, GlobalResourceKey.IconSizeSM);
smallStyle.Add(addOnContentIconStyle);
}
smallStyle.Add(LineEdit.FontSizeProperty, LineEditResourceKey.InputFontSizeSM);
smallStyle.Add(LineEdit.LineHeightProperty, GlobalResourceKey.FontHeightSM);
smallStyle.Add(LineEdit.CornerRadiusProperty, GlobalResourceKey.BorderRadiusSM);

View File

@ -1,6 +1,59 @@
namespace AtomUI.Controls;
using AtomUI.Theme.Data;
using AtomUI.Theme.Styling;
using AtomUI.Utils;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
namespace AtomUI.Controls;
public enum SearchEditButtonStyle
{
Default,
Primary
}
public class SearchEdit : LineEdit
{
#region
public static readonly StyledProperty<SearchEditButtonStyle> SearchButtonStyleProperty =
AvaloniaProperty.Register<SearchEdit, SearchEditButtonStyle>(nameof(SearchButtonStyle), SearchEditButtonStyle.Default);
public static readonly StyledProperty<string> SearchButtonTextProperty =
AvaloniaProperty.Register<SearchEdit, string>(nameof(SearchButtonText));
public SearchEditButtonStyle SearchButtonStyle
{
get => GetValue(SearchButtonStyleProperty);
set => SetValue(SearchButtonStyleProperty, value);
}
public object? SearchButtonText
{
get => GetValue(SearchButtonTextProperty);
set => SetValue(SearchButtonTextProperty, value);
}
#endregion
private Rect? _originRect;
protected override void NotifyAddOnBorderInfoCalculated()
{
RightAddOnBorderThickness = BorderThickness;
}
protected override Size ArrangeOverride(Size finalSize)
{
var size = base.ArrangeOverride(finalSize);
if (_originRect is null) {
_originRect = _rightAddOnPresenter?.Bounds;
}
if (_rightAddOnPresenter is not null && _originRect.HasValue) {
_rightAddOnPresenter.Arrange(_originRect.Value.Inflate(new Thickness(1, 0, 0, 0)));
}
return size;
}
}

View File

@ -0,0 +1,85 @@
using AtomUI.Theme.Styling;
using AtomUI.Utils;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using Avalonia.Styling;
namespace AtomUI.Controls;
[ControlThemeProvider]
internal class SearchEditTheme : LineEditTheme
{
public SearchEditTheme() : base(typeof(SearchEdit)) { }
protected override void BuildRightAddOn(Grid layout, INameScope scope)
{
var searchIcon = new PathIcon()
{
Kind = "SearchOutlined"
};
TokenResourceBinder.CreateGlobalTokenBinding(searchIcon, PathIcon.NormalFilledBrushProperty, GlobalResourceKey.ColorIcon);
var rightAddOnContentPresenter = new Button()
{
Name = RightAddOnPart,
Focusable = false,
Icon = searchIcon
};
CreateTemplateParentBinding(rightAddOnContentPresenter, Button.ContentProperty,
SearchEdit.RightAddOnProperty);
CreateTemplateParentBinding(rightAddOnContentPresenter, Button.BorderThicknessProperty,
SearchEdit.RightAddOnBorderThicknessProperty);
CreateTemplateParentBinding(rightAddOnContentPresenter, Button.CornerRadiusProperty,
SearchEdit.RightAddOnCornerRadiusProperty);
CreateTemplateParentBinding(rightAddOnContentPresenter, Button.TextProperty,
SearchEdit.SearchButtonTextProperty);
CreateTemplateParentBinding(rightAddOnContentPresenter, Button.SizeTypeProperty,
SearchEdit.SizeTypeProperty);
rightAddOnContentPresenter.RegisterInNameScope(scope);
layout.Children.Add(rightAddOnContentPresenter);
Grid.SetColumn(rightAddOnContentPresenter, 2);
}
protected override void BuildStyles()
{
base.BuildStyles();
var decoratorStyle = new Style(selector => selector.Nesting().Template().Name(LineEditKernelDecoratorPart));
decoratorStyle.Add(Border.ZIndexProperty, NormalZIndex);
Add(decoratorStyle);
var decoratorHoverOrFocusStyle = new Style(selector => Selectors.Or(selector.Nesting().Template().Name(LineEditKernelDecoratorPart).Class(StdPseudoClass.FocusWithIn),
selector.Nesting().Template().Name(LineEditKernelDecoratorPart).Class(StdPseudoClass.PointerOver)));
decoratorHoverOrFocusStyle.Add(Border.ZIndexProperty, ActivatedZIndex);
Add(decoratorHoverOrFocusStyle);
var searchButtonStyle = new Style(selector => selector.Nesting().Template().Name(RightAddOnPart));
searchButtonStyle.Add(Border.ZIndexProperty, NormalZIndex);
Add(searchButtonStyle);
var searchButtonStyleHoverOrFocusStyle = new Style(selector => Selectors.Or(selector.Nesting().Template().Name(RightAddOnPart).Class(StdPseudoClass.Pressed),
selector.Nesting().Template().Name(RightAddOnPart).Class(StdPseudoClass.PointerOver)));
searchButtonStyleHoverOrFocusStyle.Add(Border.ZIndexProperty, ActivatedZIndex);
Add(searchButtonStyleHoverOrFocusStyle);
// Icon button
var iconSearchButtonStyle = new Style(selector => selector.Nesting().PropertyEquals(SearchEdit.SearchButtonStyleProperty, SearchEditButtonStyle.Default));
{
var buttonStyle = new Style(selector => selector.Nesting().Template().Name(RightAddOnPart));
buttonStyle.Add(Button.IsIconVisibleProperty, true);
buttonStyle.Add(Button.ButtonTypeProperty, ButtonType.Default);
iconSearchButtonStyle.Add(buttonStyle);
}
Add(iconSearchButtonStyle);
// primary button
var primarySearchButtonStyle = new Style(selector => selector.Nesting().PropertyEquals(SearchEdit.SearchButtonStyleProperty, SearchEditButtonStyle.Primary));
{
var buttonStyle = new Style(selector => selector.Nesting().Template().Name(RightAddOnPart));
buttonStyle.Add(Button.IsIconVisibleProperty, false);
buttonStyle.Add(Button.ButtonTypeProperty, ButtonType.Primary);
primarySearchButtonStyle.Add(buttonStyle);
}
Add(primarySearchButtonStyle);
}
}