feat: WIP.

This commit is contained in:
Zhang Dian
2024-06-05 10:31:56 +08:00
parent 0a30d01b7d
commit fd7010967e
7 changed files with 67 additions and 51 deletions

View File

@@ -14,7 +14,6 @@
<Grid ColumnDefinitions="*, 300"> <Grid ColumnDefinitions="*, 300">
<Grid Grid.Column="0"> <Grid Grid.Column="0">
<StackPanel> <StackPanel>
<u:RatingCharacter />
<u:Rating <u:Rating
AllowClear="{Binding AllowClear }" AllowClear="{Binding AllowClear }"
AllowHalf="{Binding AllowHalf }" AllowHalf="{Binding AllowHalf }"

View File

@@ -13,8 +13,8 @@ public partial class RatingDemoViewModel : ViewModelBase
[ObservableProperty] private double _value; [ObservableProperty] private double _value;
// [ObservableProperty] private object _character; // [ObservableProperty] private object _character;
[ObservableProperty] private int _count = 10; [ObservableProperty] private int _count = 5;
[ObservableProperty] private double _defaultValue = 5.5; [ObservableProperty] private double _defaultValue = 2.3;
public ObservableCollection<string> Tooltips { get; set; } = ["1", "2", "3", "4", "5"]; public ObservableCollection<string> Tooltips { get; set; } = ["1", "2", "3", "4", "5"];
} }

View File

@@ -3,7 +3,7 @@
xmlns:u="https://irihi.tech/ursa"> xmlns:u="https://irihi.tech/ursa">
<ControlTheme x:Key="{x:Type u:RatingCharacter}" TargetType="u:RatingCharacter"> <ControlTheme x:Key="{x:Type u:RatingCharacter}" TargetType="u:RatingCharacter">
<Setter Property="Foreground" Value="{DynamicResource RatingCharacterUnSelectedForeground}" /> <Setter Property="Foreground" Value="{DynamicResource RatingCharacterUnSelectedForeground}" />
<Setter Property="Background" Value="{DynamicResource RatingCharacterUnSelectedForeground}" /> <Setter Property="Background" Value="{DynamicResource RatingCharacterBackground}" />
<Setter Property="Cursor" Value="Hand" /> <Setter Property="Cursor" Value="Hand" />
<Setter Property="VerticalAlignment" Value="Stretch" /> <Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="Template"> <Setter Property="Template">
@@ -15,7 +15,6 @@
Data="{DynamicResource RatingStarIconGlyph}" Data="{DynamicResource RatingStarIconGlyph}"
Fill="{TemplateBinding Background}" /> Fill="{TemplateBinding Background}" />
<Border Name="{x:Static u:RatingCharacter.PART_IconGlyph}" <Border Name="{x:Static u:RatingCharacter.PART_IconGlyph}"
IsVisible="True"
ClipToBounds="True"> ClipToBounds="True">
<Path Width="24" <Path Width="24"
Height="24" Height="24"
@@ -32,15 +31,7 @@
<Setter Property="RenderTransform" Value="scale(1.1)" /> <Setter Property="RenderTransform" Value="scale(1.1)" />
</Style> </Style>
<Style Selector="^:selected"> <Style Selector="^:selected">
<Setter Property="Foreground" Value="{DynamicResource RatingCharacterSelectedForeground}" /> <Setter Property="Foreground" Value="{DynamicResource RatingCharacterForeground}" />
</Style>
<Style Selector="^:half">
<!-- <Setter Property="Foreground"> -->
<!-- <LinearGradientBrush StartPoint="0%,0%" EndPoint="0%,100%"> -->
<!-- <GradientStop Color="#6b4c1b" Offset="0" /> -->
<!-- <GradientStop Color="#291e10" Offset="1" /> -->
<!-- </LinearGradientBrush> -->
<!-- </Setter> -->
</Style> </Style>
</ControlTheme> </ControlTheme>

View File

@@ -1,4 +1,5 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<SolidColorBrush x:Key="RatingCharacterUnSelectedForeground" Opacity="0.12" Color="White" /> <SolidColorBrush x:Key="RatingCharacterUnSelectedForeground" Color="Transparent" />
<SolidColorBrush x:Key="RatingCharacterSelectedForeground" Color="#FDDE43" /> <SolidColorBrush x:Key="RatingCharacterForeground" Color="#FDDE43" />
<SolidColorBrush x:Key="RatingCharacterBackground" Opacity="0.12" Color="White" />
</ResourceDictionary> </ResourceDictionary>

View File

@@ -1,4 +1,5 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<SolidColorBrush x:Key="RatingCharacterUnSelectedForeground" Opacity="0.05" Color="#2E3238" /> <SolidColorBrush x:Key="RatingCharacterUnSelectedForeground" Color="Transparent" />
<SolidColorBrush x:Key="RatingCharacterSelectedForeground" Color="#FAC800" /> <SolidColorBrush x:Key="RatingCharacterForeground" Color="#FAC800" />
<SolidColorBrush x:Key="RatingCharacterBackground" Opacity="0.05" Color="#2E3238" />
</ResourceDictionary> </ResourceDictionary>

View File

@@ -137,7 +137,11 @@ public class Rating : TemplatedControl
private void OnValueChanged(AvaloniaPropertyChangedEventArgs e) private void OnValueChanged(AvaloniaPropertyChangedEventArgs e)
{ {
UpdateItems((int)Value - 1); if (e.NewValue is double newValue)
{
UpdateItemsByValue(newValue);
AdjustWidth(newValue);
}
} }
private void OnCountChanged(AvaloniaPropertyChangedEventArgs e) private void OnCountChanged(AvaloniaPropertyChangedEventArgs e)
@@ -164,10 +168,8 @@ public class Rating : TemplatedControl
} }
} }
if (Value > newCount) UpdateItemsByValue(Value);
{ AdjustWidth(Value);
SetCurrentValue(ValueProperty, Math.Max(newCount, 0));
}
} }
protected override void OnApplyTemplate(TemplateAppliedEventArgs e) protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
@@ -180,7 +182,6 @@ public class Rating : TemplatedControl
Items.Add(new RatingCharacter()); Items.Add(new RatingCharacter());
} }
UpdateItems((int)DefaultValue - 1);
if (DefaultValue > Count) if (DefaultValue > Count)
{ {
SetCurrentValue(ValueProperty, Math.Max(Count, 0)); SetCurrentValue(ValueProperty, Math.Max(Count, 0));
@@ -207,15 +208,15 @@ public class Rating : TemplatedControl
} }
} }
UpdateItems(index); UpdateItemsByIndex(index);
} }
protected override void OnPointerExited(PointerEventArgs e) protected override void OnPointerExited(PointerEventArgs e)
{ {
UpdateItems((int)Value - 1); UpdateItemsByValue(Value);
} }
public void Select(RatingCharacter o) public void PointerReleasedHandler(RatingCharacter o)
{ {
var index = Items.IndexOf(o); var index = Items.IndexOf(o);
double newValue = index + 1; double newValue = index + 1;
@@ -226,23 +227,25 @@ public class Rating : TemplatedControl
if (AllowClear && Math.Abs(Value - newValue) < Tolerance) if (AllowClear && Math.Abs(Value - newValue) < Tolerance)
{ {
UpdateItems(-1); UpdateItemsByValue(-1);
SetCurrentValue(ValueProperty, 0); SetCurrentValue(ValueProperty, 0);
} }
else else
{ {
UpdateItems(index); UpdateItemsByValue(newValue);
SetCurrentValue(ValueProperty, newValue); SetCurrentValue(ValueProperty, newValue);
} }
} }
private void UpdateItems(int index) private void UpdateItemsByIndex(int index)
{ {
var isInt = Math.Abs(Value - Math.Floor(Value)) < Tolerance;
for (var i = 0; i <= index && i < Items.Count; i++) for (var i = 0; i <= index && i < Items.Count; i++)
{ {
if (Items[i] is RatingCharacter item) if (Items[i] is RatingCharacter item)
{ {
item.Select(true); item.Select(true);
item.IsHalf = !isInt && i == index;
} }
} }
@@ -251,6 +254,34 @@ public class Rating : TemplatedControl
if (Items[i] is RatingCharacter item) if (Items[i] is RatingCharacter item)
{ {
item.Select(false); item.Select(false);
item.IsHalf = false;
}
}
}
private void UpdateItemsByValue(double newValue)
{
var index = (int)Math.Ceiling(newValue - 1);
UpdateItemsByIndex(index);
}
private void AdjustWidth(double newValue)
{
var ratio = Math.Abs(newValue - Math.Floor(newValue));
foreach (var character in Items)
{
if (character is RatingCharacter item)
{
if (item.IsHalf)
{
item.Ratio = ratio;
}
else
{
item.Ratio = 1;
}
item.AdjustWidth();
} }
} }
} }

View File

@@ -6,13 +6,12 @@ using Avalonia.LogicalTree;
namespace Ursa.Controls; namespace Ursa.Controls;
[PseudoClasses(PC_Selected, PC_Half)] [PseudoClasses(PC_Selected)]
[TemplatePart(PART_IconGlyph, typeof(Control))] [TemplatePart(PART_IconGlyph, typeof(Control))]
public class RatingCharacter : TemplatedControl public class RatingCharacter : TemplatedControl
{ {
public const string PART_IconGlyph = "PART_IconGlyph"; public const string PART_IconGlyph = "PART_IconGlyph";
protected const string PC_Selected = ":selected"; protected const string PC_Selected = ":selected";
protected const string PC_Half = ":half";
private Control? _icon; private Control? _icon;
@@ -23,13 +22,14 @@ public class RatingCharacter : TemplatedControl
get => _isHalf; get => _isHalf;
set set
{ {
if (_isHalf == value) return;
_isHalf = value; _isHalf = value;
if (_icon is null) return; if (_icon is null) return;
_icon.Width = value ? Bounds.Width / 2 : Bounds.Width; _icon.Width = value ? Bounds.Width * 0.5 : Bounds.Width;
} }
} }
internal double Ratio { get; set; }
protected override void OnApplyTemplate(TemplateAppliedEventArgs e) protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{ {
base.OnApplyTemplate(e); base.OnApplyTemplate(e);
@@ -45,32 +45,25 @@ public class RatingCharacter : TemplatedControl
protected override void OnPointerMoved(PointerEventArgs e) protected override void OnPointerMoved(PointerEventArgs e)
{ {
var p = e.GetPosition(this); var p = e.GetPosition(this);
var flag = p.X < Bounds.Width / 2; IsHalf = p.X < Bounds.Width * 0.5;
PseudoClasses.Set(PC_Half, flag);
IsHalf = flag;
// if (flag)
// {
// _icon.Width = Bounds.Width / 2;
// }
// else
// {
// _icon.Width = Bounds.Width;
// }
} }
// protected override void OnPointerExited(PointerEventArgs e)
// {
// // _icon.Width = Bounds.Width;
// }
protected override void OnPointerReleased(PointerReleasedEventArgs e) protected override void OnPointerReleased(PointerReleasedEventArgs e)
{ {
var parent = this.GetLogicalAncestors().OfType<Rating>().FirstOrDefault(); var parent = this.GetLogicalAncestors().OfType<Rating>().FirstOrDefault();
parent?.Select(this); parent?.PointerReleasedHandler(this);
} }
public void Select(bool value) public void Select(bool value)
{ {
PseudoClasses.Set(PC_Selected, value); PseudoClasses.Set(PC_Selected, value);
} }
public void AdjustWidth()
{
if (_icon is not null)
{
_icon.Width = Bounds.Width * Ratio;
}
}
} }