feat: Add Badge styles and demos.
This commit is contained in:
1 parent
4cd78a4b3f
commit
905bc92825
7 files changed
+383
-1
No files matched your search
@@ -55,7 +55,8 @@
|
||||
[ "ProgressBar", "ProgressBarDemo", "Brush.ProgressBar", "", "Feedback" ],
|
||||
[ "Rate", "RateDemo", "Brush.Favorite", "", "Feedback" ],
|
||||
[ "Loading", "LoadingDemo", "Brush.Loading", "", "Feedback" ],
|
||||
[ "Tag", "TagDemo", "Brush.Tag", "", "DataDisplay" ]
|
||||
[ "Tag", "TagDemo", "Brush.Tag", "", "DataDisplay" ],
|
||||
[ "Badge", "BadgeDemo", "Brush.CheckDot", "", "DataDisplay" ]
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,49 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:hc="https://handyorg.github.io/handycontrol"
|
||||
x:Class="HandyControlDemo.UserControl.BadgeDemo"
|
||||
Background="{DynamicResource RegionBrush}">
|
||||
<ScrollViewer>
|
||||
<hc:UniformSpacingPanel Margin="32"
|
||||
Spacing="32"
|
||||
ChildWrapping="Wrap"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center">
|
||||
<hc:Badge Text="New"
|
||||
BadgeMargin="0,-14,-20,0"
|
||||
Height="30">
|
||||
<Button Content="Comment" />
|
||||
</hc:Badge>
|
||||
<hc:Badge Text="New"
|
||||
BadgeMargin="0,-14,-20,0"
|
||||
Height="30"
|
||||
Theme="{StaticResource BadgeDanger}">
|
||||
<Button Content="Comment" />
|
||||
</hc:Badge>
|
||||
<hc:Badge Name="CountBadge"
|
||||
Value="0"
|
||||
BadgeMargin="0,-14,-10,0"
|
||||
Height="30"
|
||||
Theme="{StaticResource BadgePrimary}">
|
||||
<Button Name="CountButton"
|
||||
Content="Click to Count" />
|
||||
</hc:Badge>
|
||||
<hc:Badge Value="100"
|
||||
BadgeMargin="0,-14,-20,0"
|
||||
Height="30"
|
||||
Theme="{StaticResource BadgeDanger}">
|
||||
<Button Content="Comment" />
|
||||
</hc:Badge>
|
||||
<hc:Badge Status="Dot"
|
||||
Height="30"
|
||||
Theme="{StaticResource BadgeDanger}">
|
||||
<Button Content="Reply" />
|
||||
</hc:Badge>
|
||||
<hc:Badge Status="Processing"
|
||||
Height="30"
|
||||
Theme="{StaticResource BadgeDanger}">
|
||||
<Button Content="Reply" />
|
||||
</hc:Badge>
|
||||
</hc:UniformSpacingPanel>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,20 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using HandyControl.Controls;
|
||||
|
||||
namespace HandyControlDemo.UserControl;
|
||||
|
||||
public partial class BadgeDemo : Avalonia.Controls.UserControl
|
||||
{
|
||||
public BadgeDemo()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
var badge = this.FindControl<Badge>("CountBadge");
|
||||
var button = this.FindControl<Button>("CountButton");
|
||||
if (button != null && badge != null)
|
||||
{
|
||||
button.Click += (_, _) => badge.Value += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
using System;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// 标记
|
||||
/// </summary>
|
||||
public class Badge : ContentControl
|
||||
{
|
||||
private int? _originalValue;
|
||||
|
||||
public static readonly RoutedEvent<FunctionEventArgs<int>> ValueChangedEvent =
|
||||
RoutedEvent.Register<Badge, FunctionEventArgs<int>>(nameof(ValueChanged), RoutingStrategies.Bubble);
|
||||
|
||||
public event EventHandler<FunctionEventArgs<int>> ValueChanged
|
||||
{
|
||||
add => AddHandler(ValueChangedEvent, value);
|
||||
remove => RemoveHandler(ValueChangedEvent, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<string?> TextProperty =
|
||||
AvaloniaProperty.Register<Badge, string?>(nameof(Text), "0");
|
||||
|
||||
public string? Text
|
||||
{
|
||||
get => GetValue(TextProperty);
|
||||
set => SetValue(TextProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<int> ValueProperty =
|
||||
AvaloniaProperty.Register<Badge, int>(nameof(Value));
|
||||
|
||||
public int Value
|
||||
{
|
||||
get => GetValue(ValueProperty);
|
||||
set => SetValue(ValueProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<BadgeStatus> StatusProperty =
|
||||
AvaloniaProperty.Register<Badge, BadgeStatus>(nameof(Status));
|
||||
|
||||
public BadgeStatus Status
|
||||
{
|
||||
get => GetValue(StatusProperty);
|
||||
set => SetValue(StatusProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<int> MaximumProperty =
|
||||
AvaloniaProperty.Register<Badge, int>(nameof(Maximum), 99);
|
||||
|
||||
public int Maximum
|
||||
{
|
||||
get => GetValue(MaximumProperty);
|
||||
set => SetValue(MaximumProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<Thickness> BadgeMarginProperty =
|
||||
AvaloniaProperty.Register<Badge, Thickness>(nameof(BadgeMargin));
|
||||
|
||||
public Thickness BadgeMargin
|
||||
{
|
||||
get => GetValue(BadgeMarginProperty);
|
||||
set => SetValue(BadgeMarginProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<bool> ShowBadgeProperty =
|
||||
AvaloniaProperty.Register<Badge, bool>(nameof(ShowBadge), true);
|
||||
|
||||
public bool ShowBadge
|
||||
{
|
||||
get => GetValue(ShowBadgeProperty);
|
||||
set => SetValue(ShowBadgeProperty, value);
|
||||
}
|
||||
|
||||
static Badge()
|
||||
{
|
||||
ValueProperty.Changed.AddClassHandler<Badge>((badge, e) => badge.OnValueChanged(e));
|
||||
MaximumProperty.Changed.AddClassHandler<Badge>((badge, _) => badge.UpdateText(badge.Value));
|
||||
}
|
||||
|
||||
private void OnValueChanged(AvaloniaPropertyChangedEventArgs e)
|
||||
{
|
||||
var v = e.GetNewValue<int>();
|
||||
UpdateText(v);
|
||||
|
||||
if (IsLoaded)
|
||||
{
|
||||
RaiseEvent(new FunctionEventArgs<int>(ValueChangedEvent, this) { Info = v });
|
||||
}
|
||||
else
|
||||
{
|
||||
_originalValue = v;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateText(int v)
|
||||
{
|
||||
SetCurrentValue(TextProperty, v <= Maximum ? v.ToString() : $"{Maximum}+");
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate(Avalonia.Controls.Primitives.TemplateAppliedEventArgs e)
|
||||
{
|
||||
base.OnApplyTemplate(e);
|
||||
|
||||
if (_originalValue != null)
|
||||
{
|
||||
RaiseEvent(new FunctionEventArgs<int>(ValueChangedEvent, this) { Info = _originalValue.Value });
|
||||
_originalValue = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace HandyControl.Data;
|
||||
|
||||
public enum BadgeStatus
|
||||
{
|
||||
Text,
|
||||
Dot,
|
||||
Processing
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
<ResourceDictionary xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:ClassModifier="internal"
|
||||
xmlns:hc="clr-namespace:HandyControl.Controls">
|
||||
|
||||
<ControlTheme x:Key="BadgeBaseStyle"
|
||||
TargetType="hc:Badge">
|
||||
<Setter Property="Focusable"
|
||||
Value="False" />
|
||||
<Setter Property="ClipToBounds"
|
||||
Value="False" />
|
||||
<Setter Property="Background"
|
||||
Value="{DynamicResource SecondaryRegionBrush}" />
|
||||
<Setter Property="Foreground"
|
||||
Value="{DynamicResource TextIconBrush}" />
|
||||
<Setter Property="BorderThickness"
|
||||
Value="1" />
|
||||
<Setter Property="BorderBrush"
|
||||
Value="{DynamicResource RegionBrush}" />
|
||||
<Setter Property="Padding"
|
||||
Value="6,2" />
|
||||
<Setter Property="HorizontalContentAlignment"
|
||||
Value="Right" />
|
||||
<Setter Property="VerticalContentAlignment"
|
||||
Value="Top" />
|
||||
<Setter Property="BadgeMargin"
|
||||
Value="0,-10,-10,0" />
|
||||
|
||||
<!-- Default: Text template -->
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate TargetType="hc:Badge">
|
||||
<Panel>
|
||||
<ContentPresenter Content="{TemplateBinding Content}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}" />
|
||||
<Border Name="PART_Badge"
|
||||
IsVisible="{TemplateBinding ShowBadge}"
|
||||
RenderTransformOrigin="50%,50%"
|
||||
Theme="{StaticResource BorderCircular}"
|
||||
Margin="{TemplateBinding BadgeMargin}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}">
|
||||
<Border.RenderTransform>
|
||||
<ScaleTransform />
|
||||
</Border.RenderTransform>
|
||||
<ContentPresenter Content="{TemplateBinding Text}"
|
||||
Margin="{TemplateBinding Padding}" />
|
||||
</Border>
|
||||
</Panel>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
|
||||
<!-- Dot template -->
|
||||
<Style Selector="^[Status=Dot]">
|
||||
<Setter Property="BorderBrush"
|
||||
Value="{DynamicResource BorderBrush}" />
|
||||
<Setter Property="BadgeMargin"
|
||||
Value="0,-5,-5,0" />
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate TargetType="hc:Badge">
|
||||
<Panel>
|
||||
<ContentPresenter Content="{TemplateBinding Content}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}" />
|
||||
<Border IsVisible="{TemplateBinding ShowBadge}"
|
||||
Margin="{TemplateBinding BadgeMargin}"
|
||||
Width="10"
|
||||
Height="10"
|
||||
CornerRadius="5"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}" />
|
||||
</Panel>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- Processing template -->
|
||||
<Style Selector="^[Status=Processing]">
|
||||
<Setter Property="BorderBrush"
|
||||
Value="{DynamicResource BorderBrush}" />
|
||||
<Setter Property="BadgeMargin"
|
||||
Value="0,-5,-5,0" />
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate TargetType="hc:Badge">
|
||||
<Panel>
|
||||
<ContentPresenter Content="{TemplateBinding Content}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}" />
|
||||
<Ellipse Name="PART_Pulse"
|
||||
IsVisible="{TemplateBinding ShowBadge}"
|
||||
Width="10"
|
||||
Height="10"
|
||||
Fill="{TemplateBinding Background}"
|
||||
RenderTransformOrigin="50%,50%"
|
||||
Margin="{TemplateBinding BadgeMargin}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
|
||||
<Ellipse.RenderTransform>
|
||||
<ScaleTransform />
|
||||
</Ellipse.RenderTransform>
|
||||
</Ellipse>
|
||||
<Border IsVisible="{TemplateBinding ShowBadge}"
|
||||
Margin="{TemplateBinding BadgeMargin}"
|
||||
Width="10"
|
||||
Height="10"
|
||||
CornerRadius="5"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}" />
|
||||
</Panel>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style Selector="^[Status=Processing] /template/ Ellipse#PART_Pulse">
|
||||
<Style.Animations>
|
||||
<Animation IterationCount="Infinite"
|
||||
Easing="SineEaseOut"
|
||||
Duration="0:0:1">
|
||||
<KeyFrame Cue="0%">
|
||||
<Setter Property="ScaleTransform.ScaleX"
|
||||
Value="1" />
|
||||
<Setter Property="ScaleTransform.ScaleY"
|
||||
Value="1" />
|
||||
<Setter Property="Opacity"
|
||||
Value="1" />
|
||||
</KeyFrame>
|
||||
<KeyFrame Cue="100%">
|
||||
<Setter Property="ScaleTransform.ScaleX"
|
||||
Value="2" />
|
||||
<Setter Property="ScaleTransform.ScaleY"
|
||||
Value="2" />
|
||||
<Setter Property="Opacity"
|
||||
Value="0" />
|
||||
</KeyFrame>
|
||||
</Animation>
|
||||
</Style.Animations>
|
||||
</Style>
|
||||
</ControlTheme>
|
||||
|
||||
<ControlTheme x:Key="{x:Type hc:Badge}"
|
||||
BasedOn="{StaticResource BadgeBaseStyle}"
|
||||
TargetType="hc:Badge">
|
||||
<Setter Property="Foreground"
|
||||
Value="{DynamicResource PrimaryTextBrush}" />
|
||||
</ControlTheme>
|
||||
|
||||
<ControlTheme x:Key="BadgePrimary"
|
||||
BasedOn="{StaticResource BadgeBaseStyle}"
|
||||
TargetType="hc:Badge">
|
||||
<Setter Property="Background"
|
||||
Value="{DynamicResource PrimaryBrush}" />
|
||||
</ControlTheme>
|
||||
|
||||
<ControlTheme x:Key="BadgeSuccess"
|
||||
BasedOn="{StaticResource BadgeBaseStyle}"
|
||||
TargetType="hc:Badge">
|
||||
<Setter Property="Background"
|
||||
Value="{DynamicResource SuccessBrush}" />
|
||||
</ControlTheme>
|
||||
|
||||
<ControlTheme x:Key="BadgeInfo"
|
||||
BasedOn="{StaticResource BadgeBaseStyle}"
|
||||
TargetType="hc:Badge">
|
||||
<Setter Property="Background"
|
||||
Value="{DynamicResource InfoBrush}" />
|
||||
</ControlTheme>
|
||||
|
||||
<ControlTheme x:Key="BadgeWarning"
|
||||
BasedOn="{StaticResource BadgeBaseStyle}"
|
||||
TargetType="hc:Badge">
|
||||
<Setter Property="Background"
|
||||
Value="{DynamicResource WarningBrush}" />
|
||||
</ControlTheme>
|
||||
|
||||
<ControlTheme x:Key="BadgeDanger"
|
||||
BasedOn="{StaticResource BadgeBaseStyle}"
|
||||
TargetType="hc:Badge">
|
||||
<Setter Property="Background"
|
||||
Value="{DynamicResource DangerBrush}" />
|
||||
</ControlTheme>
|
||||
|
||||
</ResourceDictionary>
|
||||
@@ -71,6 +71,7 @@
|
||||
<MergeResourceInclude Source="avares://HandyControl/Themes/Styles/ButtonGroup.axaml" />
|
||||
<MergeResourceInclude Source="avares://HandyControl/Themes/Styles/Gravatar.axaml" />
|
||||
<MergeResourceInclude Source="avares://HandyControl/Themes/Styles/Tag.axaml" />
|
||||
<MergeResourceInclude Source="avares://HandyControl/Themes/Styles/Badge.axaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Styles.Resources>
|
||||
|
||||
Reference in new issue
Block a user