Added AvatarView and Slider controls

This commit is contained in:
Javier Suárez Ruiz 2022-04-15 12:17:03 +02:00
Родитель 236b2b05ed
Коммит aafc4aa8df
13 изменённых файлов: 1077 добавлений и 6 удалений

Просмотреть файл

@ -6,13 +6,16 @@ namespace AlohaKit.Gallery.ViewModels
public class MainViewModel : BaseGalleryViewModel public class MainViewModel : BaseGalleryViewModel
{ {
protected override IEnumerable<SectionModel> CreateItems() => new[] protected override IEnumerable<SectionModel> CreateItems() => new[]
{ {
new SectionModel(typeof(AvatarView), "Avatar",
"The Avatar control displays the initials of a person, entity, or group on top of a colored circular background."),
new SectionModel(typeof(LoadingView), "BusyIndicator", new SectionModel(typeof(LoadingView), "BusyIndicator",
"It can be used to indicate busy status during app loading, data processing, etc."), "It can be used to indicate busy status during app loading, data processing, etc."),
new SectionModel(typeof(ButtonView), "Button", new SectionModel(typeof(ButtonView), "Button",
"The Button responds to a tap or click."), "The Button responds to a tap or click."),
new SectionModel(typeof(ProgressBarView), "ProgressBar", new SectionModel(typeof(ProgressBarView), "ProgressBar",
"The ProgressRadial is a control that indicates the progress of a task."), "The ProgressRadial is a control that indicates the progress of a task."),
@ -21,6 +24,9 @@ namespace AlohaKit.Gallery.ViewModels
new SectionModel(typeof(RatingView), "Rating", new SectionModel(typeof(RatingView), "Rating",
"Rating is a control that allows users to rate by selecting number of items from a predefined number of items."), "Rating is a control that allows users to rate by selecting number of items from a predefined number of items."),
new SectionModel(typeof(SliderView), "Slider",
"The Slider is a horizontal bar that can be manipulated by the user to select a double value from a continuous range."),
new SectionModel(typeof(ToggleSwitchView), "ToggleSwitch", new SectionModel(typeof(ToggleSwitchView), "ToggleSwitch",
"The ToggleSwitch is a horizontal toggle button that can be manipulated by the user to toggle between on and off states."), "The ToggleSwitch is a horizontal toggle button that can be manipulated by the user to toggle between on and off states."),

Просмотреть файл

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="AlohaKit.Gallery.AvatarView"
xmlns:controls="clr-namespace:AlohaKit.Controls;assembly=AlohaKit"
Title="Avatar">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="SettingsTextStyle" TargetType="Label">
<Setter Property="FontSize" Value="9" />
</Style>
<Style x:Key="SettingsEntryStyle" TargetType="Entry">
<Setter Property="VerticalOptions" Value="Center" />
<Setter Property="WidthRequest" Value="80" />
<Setter Property="Margin" Value="6, 0" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- DESCRIPTION -->
<StackLayout
Style="{StaticResource SectionContainerStyle}">
<Label
Text="The Avatar control displays the initials of a person, entity, or group on top of a colored circular background."/>
</StackLayout>
<!-- FEATURES -->
<StackLayout
Grid.Row="1"
BackgroundColor="{AppThemeBinding Light={StaticResource LightBackgroundSecondaryColor}, Dark={StaticResource DarkBackgroundSecondaryColor}}"
Style="{StaticResource SectionContainerStyle}">
<Label
Text="Features"
Style="{StaticResource SectionTitleStyle}"/>
<Label
Text="- Can choose from several predefined sizes."/>
<Label
Text="- Allow to customize the background with a gradient."/>
<Label
Text="- Allow to customize the fill with a gradient."/>
</StackLayout>
<!-- SETTINGS -->
<StackLayout
Grid.Row="2"
Style="{StaticResource SectionContainerStyle}">
<Label
Text="Settings"
Style="{StaticResource SectionTitleStyle}"/>
<StackLayout
Orientation="Horizontal"
Margin="0, 6">
<Label
Text="Fill Start Color"
VerticalOptions="Center"
Style="{StaticResource SettingsTextStyle}"/>
<Entry
x:Name="FillStartColorEntry"
Placeholder="Background Color"
Text="#DD5E89"
TextChanged="OnFillStartColorEntryTextChanged"
Style="{StaticResource SettingsEntryStyle}"/>
<Label
Text="Fill End Color"
VerticalOptions="Center"
Style="{StaticResource SettingsTextStyle}"/>
<Entry
x:Name="FillEndColorEntry"
Placeholder="Color"
Text="#F7BB97"
TextChanged="OnFillEndColorEntryTextChanged"
Style="{StaticResource SettingsEntryStyle}"/>
</StackLayout>
</StackLayout>
<controls:Avatar
Grid.Row="3"
x:Name="Avatar"
HorizontalOptions="Center"
Name="Javier Suarez"/>
</Grid>
</ContentPage>

Просмотреть файл

@ -0,0 +1,59 @@
namespace AlohaKit.Gallery;
public partial class AvatarView : ContentPage
{
public AvatarView()
{
InitializeComponent();
UpdateBrushes();
}
void OnFillStartColorEntryTextChanged(object sender, TextChangedEventArgs e)
{
UpdateBrushes();
}
void OnFillEndColorEntryTextChanged(object sender, TextChangedEventArgs e)
{
UpdateBrushes();
}
void UpdateBrushes()
{
var fillStartColor = GetColorFromString(FillStartColorEntry.Text);
var fillEndColor = GetColorFromString(FillEndColorEntry.Text);
if (fillStartColor != null && fillEndColor != null)
{
FillStartColorEntry.BackgroundColor = fillStartColor;
FillEndColorEntry.BackgroundColor = fillEndColor;
Avatar.Fill = new LinearGradientBrush
{
StartPoint = new Point(0, 0),
EndPoint = new Point(1, 0),
GradientStops = new GradientStopCollection
{
new GradientStop { Color = fillStartColor, Offset = 0 },
new GradientStop { Color = fillEndColor, Offset = 1 }
}
};
}
}
Color GetColorFromString(string value)
{
if (string.IsNullOrEmpty(value))
return null;
try
{
return Color.FromArgb(value[0].Equals('#') ? value : $"#{value}");
}
catch (Exception)
{
return null;
}
}
}

Просмотреть файл

@ -0,0 +1,131 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="AlohaKit.Gallery.SliderView"
xmlns:controls="clr-namespace:AlohaKit.Controls;assembly=AlohaKit"
Title="Slider">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="SettingsTextStyle" TargetType="Label">
<Setter Property="FontSize" Value="9" />
</Style>
<Style x:Key="SettingsEntryStyle" TargetType="Entry">
<Setter Property="VerticalOptions" Value="Center" />
<Setter Property="WidthRequest" Value="80" />
<Setter Property="Margin" Value="6, 0" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- DESCRIPTION -->
<StackLayout
Style="{StaticResource SectionContainerStyle}">
<Label
Text="Slider is a horizontal bar that can be manipulated by the user to select a double value from a continuous range."/>
</StackLayout>
<!-- FEATURES -->
<StackLayout
Grid.Row="1"
BackgroundColor="{AppThemeBinding Light={StaticResource LightBackgroundSecondaryColor}, Dark={StaticResource DarkBackgroundSecondaryColor}}"
Style="{StaticResource SectionContainerStyle}">
<Label
Text="Features"
Style="{StaticResource SectionTitleStyle}"/>
<Label
Text="- All the colors can be customized supporting gradients."/>
</StackLayout>
<!-- SETTINGS -->
<StackLayout
Grid.Row="2"
Style="{StaticResource SectionContainerStyle}">
<Label
Text="Settings"
Style="{StaticResource SectionTitleStyle}"/>
<StackLayout
Orientation="Horizontal"
Margin="0, 6">
<Label
Text="MinimumBrush Start Color"
VerticalOptions="Center"
Style="{StaticResource SettingsTextStyle}"/>
<Entry
x:Name="MinimumBrushStartColorEntry"
Placeholder="MinimumBrush"
Text="#DD5E89"
TextChanged="OnMinimumBrushStartColorEntryTextChanged"
Style="{StaticResource SettingsEntryStyle}"/>
<Label
Text="MinimumBrush End Color"
VerticalOptions="Center"
Style="{StaticResource SettingsTextStyle}"/>
<Entry
x:Name="MinimumBrushEndColorEntry"
Placeholder="MinimumBrush"
Text="#F7BB97"
TextChanged="OnMinimumBrushEndColorEntryTextChanged"
Style="{StaticResource SettingsEntryStyle}"/>
</StackLayout>
<StackLayout
Orientation="Horizontal"
Margin="0, 6">
<Label
Text="MaximumBrush Start Color"
VerticalOptions="Center"
Style="{StaticResource SettingsTextStyle}"/>
<Entry
x:Name="MaximumBrushStartColorEntry"
Placeholder="MaximumBrush"
Text="#CC2B5E"
TextChanged="OnMaximumBrushStartColorEntryTextChanged"
Style="{StaticResource SettingsEntryStyle}"/>
<Label
Text="MaximumBrush End Color"
VerticalOptions="Center"
Style="{StaticResource SettingsTextStyle}"/>
<Entry
x:Name="MaximumBrushEndColorEntry"
Placeholder="Color"
Text="#753A88"
TextChanged="OnMaximumBrushEndColorEntryTextChanged"
Style="{StaticResource SettingsEntryStyle}"/>
</StackLayout>
<StackLayout
Orientation="Horizontal"
Margin="0, 6">
<Label
Text="ThumbBrush Start Color"
VerticalOptions="Center"
Style="{StaticResource SettingsTextStyle}"/>
<Entry
x:Name="ThumbBrushStartColorEntry"
Placeholder="ThumbBrush"
Text="#CCCCCC"
TextChanged="OnThumbBrushStartColorEntryTextChanged"
Style="{StaticResource SettingsEntryStyle}"/>
<Label
Text="ThumbBrush End Color"
VerticalOptions="Center"
Style="{StaticResource SettingsTextStyle}"/>
<Entry
x:Name="ThumbBrushEndColorEntry"
Placeholder="ThumbBrush"
Text="#BDC3C7"
TextChanged="OnThumbBrushEndColorEntryTextChanged"
Style="{StaticResource SettingsEntryStyle}"/>
</StackLayout>
</StackLayout>
<controls:Slider
Grid.Row="3"
x:Name="Slider" />
</Grid>
</ContentPage>

Просмотреть файл

@ -0,0 +1,119 @@
namespace AlohaKit.Gallery;
public partial class SliderView : ContentPage
{
public SliderView()
{
InitializeComponent();
UpdateBrushes();
}
void OnMinimumBrushStartColorEntryTextChanged(object sender, TextChangedEventArgs e)
{
UpdateBrushes();
}
void OnMinimumBrushEndColorEntryTextChanged(object sender, TextChangedEventArgs e)
{
UpdateBrushes();
}
void OnMaximumBrushStartColorEntryTextChanged(object sender, TextChangedEventArgs e)
{
UpdateBrushes();
}
void OnMaximumBrushEndColorEntryTextChanged(object sender, TextChangedEventArgs e)
{
UpdateBrushes();
}
void OnThumbBrushStartColorEntryTextChanged(object sender, TextChangedEventArgs e)
{
UpdateBrushes();
}
void OnThumbBrushEndColorEntryTextChanged(object sender, TextChangedEventArgs e)
{
UpdateBrushes();
}
void UpdateBrushes()
{
var minimumStartColor = GetColorFromString(MinimumBrushStartColorEntry.Text);
var minimumEndColor = GetColorFromString(MinimumBrushEndColorEntry.Text);
if (minimumStartColor != null && minimumEndColor != null)
{
MinimumBrushStartColorEntry.BackgroundColor = minimumStartColor;
MinimumBrushEndColorEntry.BackgroundColor = minimumEndColor;
Slider.MinimumBrush = new LinearGradientBrush
{
StartPoint = new Point(0, 0),
EndPoint = new Point(1, 0),
GradientStops = new GradientStopCollection
{
new GradientStop { Color = minimumStartColor, Offset = 0 },
new GradientStop { Color = minimumEndColor, Offset = 1 }
}
};
}
var maximumStartColor = GetColorFromString(MaximumBrushStartColorEntry.Text);
var maximumEndColor = GetColorFromString(MaximumBrushEndColorEntry.Text);
if (maximumStartColor != null && maximumEndColor != null)
{
MaximumBrushStartColorEntry.BackgroundColor = maximumStartColor;
MaximumBrushEndColorEntry.BackgroundColor = maximumEndColor;
Slider.MaximumBrush = new LinearGradientBrush
{
StartPoint = new Point(0, 0),
EndPoint = new Point(1, 0),
GradientStops = new GradientStopCollection
{
new GradientStop { Color = maximumStartColor, Offset = 0 },
new GradientStop { Color = maximumEndColor, Offset = 1 }
}
};
}
var thumbStartColor = GetColorFromString(ThumbBrushStartColorEntry.Text);
var thumbEndColor = GetColorFromString(ThumbBrushEndColorEntry.Text);
if (thumbStartColor != null && thumbEndColor != null)
{
ThumbBrushStartColorEntry.BackgroundColor = thumbStartColor;
ThumbBrushEndColorEntry.BackgroundColor = thumbEndColor;
Slider.ThumbBrush = new LinearGradientBrush
{
StartPoint = new Point(0, 0),
EndPoint = new Point(1, 0),
GradientStops = new GradientStopCollection
{
new GradientStop { Color = thumbStartColor, Offset = 0 },
new GradientStop { Color = thumbEndColor, Offset = 1 }
}
};
}
}
Color GetColorFromString(string value)
{
if (string.IsNullOrEmpty(value))
return null;
try
{
return Color.FromArgb(value[0].Equals('#') ? value : $"#{value}");
}
catch (Exception)
{
return null;
}
}
}

Просмотреть файл

@ -0,0 +1,172 @@
namespace AlohaKit.Controls
{
public class Avatar : GraphicsView
{
public Avatar()
{
Drawable = PersonaDrawable = new AvatarDrawable();
}
public AvatarDrawable PersonaDrawable { get; set; }
public static readonly new BindableProperty BackgroundProperty =
BindableProperty.Create(nameof(Background), typeof(Brush), typeof(Avatar), null,
propertyChanged: (bindableObject, oldValue, newValue) =>
{
if (newValue != null && bindableObject is Avatar avatar)
{
avatar.UpdateBackground();
}
});
public new Brush Background
{
get => (Brush)GetValue(BackgroundProperty);
set => SetValue(BackgroundProperty, value);
}
public static readonly BindableProperty FillProperty =
BindableProperty.Create(nameof(Fill), typeof(Brush), typeof(Avatar), new SolidColorBrush(Color.FromArgb("#4967F5")),
propertyChanged: (bindableObject, oldValue, newValue) =>
{
if (newValue != null && bindableObject is Avatar avatar)
{
avatar.UpdateFill();
}
});
public Brush Fill
{
get => (Brush)GetValue(FillProperty);
set => SetValue(FillProperty, value);
}
public static readonly BindableProperty NameProperty =
BindableProperty.Create(nameof(Name), typeof(string), typeof(Avatar), string.Empty,
propertyChanged: (bindableObject, oldValue, newValue) =>
{
if (newValue != null && bindableObject is Avatar avatar)
{
avatar.UpdateName();
}
});
public string Name
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
public static readonly BindableProperty TextColorProperty =
BindableProperty.Create(nameof(TextColor), typeof(Color), typeof(Avatar), Colors.White,
propertyChanged: (bindableObject, oldValue, newValue) =>
{
if (newValue != null && bindableObject is Avatar avatar)
{
avatar.UpdateTextColor();
}
});
public Color TextColor
{
get { return (Color)GetValue(TextColorProperty); }
set { SetValue(TextColorProperty, value); }
}
public static readonly BindableProperty AvatarSizeProperty =
BindableProperty.Create(nameof(AvatarSize), typeof(AvatarSize), typeof(Avatar), AvatarSize.Small,
propertyChanged: (bindableObject, oldValue, newValue) =>
{
if (newValue != null && bindableObject is Avatar avatar)
{
avatar.UpdateAvatarSize();
}
});
public AvatarSize AvatarSize
{
get { return (AvatarSize)GetValue(AvatarSizeProperty); }
set { SetValue(AvatarSizeProperty, value); }
}
protected override void OnParentSet()
{
base.OnParentSet();
if (Parent != null)
{
UpdateAvatarSize();
UpdateBackground();
UpdateFill();
UpdateName();
UpdateTextColor();
}
}
void UpdateAvatarSize()
{
HeightRequest = WidthRequest = AvatarSize.GetAvatarSize();
}
void UpdateBackground()
{
if (PersonaDrawable == null)
return;
PersonaDrawable.BackgroundPaint = Background;
Invalidate();
}
void UpdateFill()
{
if (PersonaDrawable == null)
return;
PersonaDrawable.FillPaint = Fill;
Invalidate();
}
void UpdateName()
{
if (PersonaDrawable == null)
return;
PersonaDrawable.Text = GetInitials(Name);
PersonaDrawable.FontSize = AvatarSize.GetInitialsFontSize();
Invalidate();
}
void UpdateTextColor()
{
if (PersonaDrawable == null)
return;
PersonaDrawable.TextColor = TextColor;
Invalidate();
}
string GetInitials(string text)
{
string result = string.Empty;
bool v = true;
for (int i = 0; i < text.Length; i++)
{
if (text[i] == ' ')
v = true;
else if (text[i] != ' ' && v)
{
result += text[i];
v = false;
}
}
return result;
}
}
}

Просмотреть файл

@ -0,0 +1,64 @@
namespace AlohaKit.Controls
{
public class AvatarDrawable : IDrawable
{
public Paint BackgroundPaint { get; set; }
public Paint FillPaint { get; set; }
public string Text { get; set; }
public Color TextColor { get; set; }
public double FontSize { get; set; }
public void Draw(ICanvas canvas, RectF dirtyRect)
{
DrawBackground(canvas, dirtyRect);
DrawFill(canvas, dirtyRect);
DrawInitials(canvas, dirtyRect);
}
public virtual void DrawBackground(ICanvas canvas, RectF dirtyRect)
{
canvas.SaveState();
if (BackgroundPaint != null)
canvas.SetFillPaint(BackgroundPaint, dirtyRect);
canvas.FillRectangle(dirtyRect);
canvas.RestoreState();
}
public virtual void DrawFill(ICanvas canvas, RectF dirtyRect)
{
canvas.SaveState();
if (FillPaint != null)
canvas.SetFillPaint(FillPaint, dirtyRect);
var x = dirtyRect.X;
var y = dirtyRect.Y;
var height = dirtyRect.Height;
var width = dirtyRect.Width;
canvas.FillEllipse(x, y, width, height);
canvas.RestoreState();
}
void DrawInitials(ICanvas canvas, RectF dirtyRect)
{
canvas.SaveState();
canvas.FontColor = TextColor;
canvas.FontSize = (float)FontSize;
var height = dirtyRect.Height;
var width = dirtyRect.Width;
canvas.DrawString(Text, 0, 0, width, height, HorizontalAlignment.Center, VerticalAlignment.Center);
canvas.RestoreState();
}
}
}

Просмотреть файл

@ -0,0 +1,9 @@
namespace AlohaKit.Controls
{
public enum AvatarSize
{
Small,
Large,
XXLarge
}
}

Просмотреть файл

@ -0,0 +1,61 @@
namespace AlohaKit.Controls
{
public static class AvatarSizeExtensions
{
public static int GetAvatarSize(this AvatarSize avatarSize)
{
switch (avatarSize)
{
case AvatarSize.Small:
default:
return 48;
case AvatarSize.Large:
return 72;
case AvatarSize.XXLarge:
return 120;
}
}
public static int GetAvatarIndicatorSize(this AvatarSize avatarSize)
{
switch (avatarSize)
{
case AvatarSize.Small:
default:
return 12;
case AvatarSize.Large:
return 20;
case AvatarSize.XXLarge:
return 36;
}
}
public static float GetAvatarIndicatorIconScale(this AvatarSize avatarSize)
{
switch (avatarSize)
{
case AvatarSize.Small:
default:
return 1.0f;
case AvatarSize.Large:
return 1.5f;
case AvatarSize.XXLarge:
return 2.5f;
}
}
public static int GetInitialsFontSize(this AvatarSize avatarSize)
{
switch (avatarSize)
{
case AvatarSize.Small:
default:
return 20;
case AvatarSize.Large:
return 28;
case AvatarSize.XXLarge:
return 42;
}
}
}
}

Просмотреть файл

@ -23,7 +23,7 @@
DrawRatingItem(canvas, dirtyRect, i); DrawRatingItem(canvas, dirtyRect, i);
} }
} }
void DrawBackground(ICanvas canvas, RectF dirtyRect) public virtual void DrawBackground(ICanvas canvas, RectF dirtyRect)
{ {
canvas.SaveState(); canvas.SaveState();
@ -34,13 +34,13 @@
canvas.RestoreState(); canvas.RestoreState();
} }
void DrawRatingItem(ICanvas canvas, RectF dirtyRect, int index) public virtual void DrawRatingItem(ICanvas canvas, RectF dirtyRect, int index)
{ {
canvas.SaveState(); canvas.SaveState();
canvas.StrokeColor = (index >= Value) ? UnSelectedStrokeColor : SelectedStrokeColor; canvas.StrokeColor = (index >= Value) ? UnSelectedStrokeColor : SelectedStrokeColor;
canvas.StrokeSize = (index >= Value) ? (float)UnSelectedStrokeWidth: (float)SelectedStrokeWidth; canvas.StrokeSize = (index >= Value) ? (float)UnSelectedStrokeWidth : (float)SelectedStrokeWidth;
canvas.FillColor = (index >= Value) ? UnSelectedFillColor : SelectedFillColor; canvas.FillColor = (index >= Value) ? UnSelectedFillColor : SelectedFillColor;
float scale = 0.85f; float scale = 0.85f;

Просмотреть файл

@ -0,0 +1,236 @@
namespace AlohaKit.Controls
{
public class Slider : GraphicsView
{
public Slider()
{
HeightRequest = 20;
WidthRequest = 120;
Drawable = SliderDrawable = new SliderDrawable();
StartInteraction += OnSliderStartInteraction;
DragInteraction += OnSliderDragInteraction;
}
public SliderDrawable SliderDrawable { get; set; }
public static readonly new BindableProperty BackgroundProperty =
BindableProperty.Create(nameof(Background), typeof(Brush), typeof(Button), null,
propertyChanged: (bindableObject, oldValue, newValue) =>
{
if (newValue != null && bindableObject is Slider slider)
{
slider.UpdateBackground();
}
});
public new Brush Background
{
get => (Brush)GetValue(BackgroundProperty);
set => SetValue(BackgroundProperty, value);
}
public static readonly BindableProperty MinimumProperty =
BindableProperty.Create(nameof(Minimum), typeof(double), typeof(Slider), 0d,
propertyChanged: (bindableObject, oldValue, newValue) =>
{
if (newValue != null && bindableObject is Slider slider)
{
slider.UpdateMinimum();
}
});
public double Minimum
{
get => (double)GetValue(MinimumProperty);
set => SetValue(MinimumProperty, value);
}
public static readonly BindableProperty MaximumProperty =
BindableProperty.Create(nameof(Maximum), typeof(double), typeof(Slider), 10d,
propertyChanged: (bindableObject, oldValue, newValue) =>
{
if (newValue != null && bindableObject is Slider slider)
{
slider.UpdateMaximum();
}
});
public double Maximum
{
get => (double)GetValue(MaximumProperty);
set => SetValue(MaximumProperty, value);
}
public static readonly BindableProperty ValueProperty =
BindableProperty.Create(nameof(Value), typeof(double), typeof(Slider), 0d,
propertyChanged: (bindableObject, oldValue, newValue) =>
{
if (newValue != null && bindableObject is Slider slider)
{
slider.UpdateValue();
slider.ValueChanged?.Invoke(slider, new ValueChangedEventArgs((double)oldValue, (double)newValue));
}
});
public double Value
{
get => (double)GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
public static readonly BindableProperty MinimumBrushProperty =
BindableProperty.Create(nameof(MinimumBrush), typeof(Brush), typeof(Slider), null,
propertyChanged: (bindableObject, oldValue, newValue) =>
{
if (newValue != null && bindableObject is Slider slider)
{
slider.UpdateMinimumBrush();
}
});
public Brush MinimumBrush
{
get => (Brush)GetValue(MinimumBrushProperty);
set => SetValue(MinimumBrushProperty, value);
}
public static readonly BindableProperty MaximumBrushProperty =
BindableProperty.Create(nameof(MaximumBrush), typeof(Brush), typeof(Slider), null,
propertyChanged: (bindableObject, oldValue, newValue) =>
{
if (newValue != null && bindableObject is Slider slider)
{
slider.UpdateMaximumBrush();
}
});
public Brush MaximumBrush
{
get => (Brush)GetValue(MaximumBrushProperty);
set => SetValue(MaximumBrushProperty, value);
}
public static readonly BindableProperty ThumbBrushProperty =
BindableProperty.Create(nameof(ThumbBrush), typeof(Brush), typeof(Slider), null,
propertyChanged: (bindableObject, oldValue, newValue) =>
{
if (newValue != null && bindableObject is Slider slider)
{
slider.UpdateThumbBrush();
}
});
public Brush ThumbBrush
{
get => (Brush)GetValue(ThumbBrushProperty);
set => SetValue(ThumbBrushProperty, value);
}
public event EventHandler<ValueChangedEventArgs> ValueChanged;
protected override void OnParentSet()
{
base.OnParentSet();
if(Parent != null)
{
UpdateBackground();
UpdateMinimum();
UpdateMaximum();
UpdateValue();
UpdateMinimumBrush();
UpdateMaximumBrush();
UpdateThumbBrush();
}
}
void UpdateBackground()
{
if (SliderDrawable == null)
return;
SliderDrawable.BackgroundPaint = Background;
Invalidate();
}
void UpdateMinimum()
{
if (SliderDrawable == null)
return;
SliderDrawable.Minimum = Minimum;
Invalidate();
}
void UpdateMaximum()
{
if (SliderDrawable == null)
return;
SliderDrawable.Maximum = Maximum;
Invalidate();
}
void UpdateValue()
{
if (SliderDrawable == null)
return;
SliderDrawable.Value = Value;
Invalidate();
}
void UpdateMinimumBrush()
{
if (SliderDrawable == null)
return;
SliderDrawable.MinimumPaint = MinimumBrush;
Invalidate();
}
void UpdateMaximumBrush()
{
if (SliderDrawable == null)
return;
SliderDrawable.MaximumPaint = MaximumBrush;
Invalidate();
}
void UpdateThumbBrush()
{
if (SliderDrawable == null)
return;
SliderDrawable.ThumbPaint = ThumbBrush;
Invalidate();
}
void OnSliderStartInteraction(object sender, TouchEventArgs args)
{
var touchPoint = args.Touches[0];
UpdateValueFromInteraction(touchPoint);
}
void OnSliderDragInteraction(object sender, TouchEventArgs args)
{
var touchPoint = args.Touches[0];
UpdateValueFromInteraction(touchPoint);
}
void UpdateValueFromInteraction(PointF touchPoint)
{
Value = touchPoint.X * Maximum / Width;
}
}
}

Просмотреть файл

@ -0,0 +1,102 @@
using AlohaKit.Extensions;
namespace AlohaKit.Controls
{
public class SliderDrawable : IDrawable
{
public Paint BackgroundPaint { get; set; }
public double Minimum { get; set; }
public double Maximum { get; set; }
public double Value { get; set; }
public Paint MinimumPaint { get; set; }
public Paint MaximumPaint { get; set; }
public Paint ThumbPaint { get; set; }
public void Draw(ICanvas canvas, RectF dirtyRect)
{
DrawBackground(canvas, dirtyRect);
DrawTrackBackground(canvas, dirtyRect);
DrawTrackProgress(canvas, dirtyRect);
DrawThumb(canvas, dirtyRect);
}
public virtual void DrawBackground(ICanvas canvas, RectF dirtyRect)
{
canvas.SaveState();
if (BackgroundPaint != null)
canvas.SetFillPaint(BackgroundPaint, dirtyRect);
canvas.FillRectangle(dirtyRect);
canvas.RestoreState();
}
public virtual void DrawTrackBackground(ICanvas canvas, RectF dirtyRect)
{
canvas.SaveState();
if(MaximumPaint != null)
canvas.SetFillPaint(MaximumPaint, dirtyRect);
var x = dirtyRect.X;
var width = dirtyRect.Width;
var height = 2;
var y = (float)((dirtyRect.Height - height) / 2);
canvas.FillRoundedRectangle(x, y, width, height, 0);
canvas.RestoreState();
}
public virtual void DrawTrackProgress(ICanvas canvas, RectF dirtyRect)
{
canvas.SaveState();
if (MinimumPaint != null)
canvas.SetFillPaint(MinimumPaint, dirtyRect);
var x = dirtyRect.X;
var value = (Value / Maximum - Minimum).Clamp(0, 1);
var width = (float)(dirtyRect.Width * value);
const float TrackSize = 2f;
var height = TrackSize;
var y = (float)((dirtyRect.Height - height) / 2);
canvas.FillRoundedRectangle(x, y, width, height, 0);
canvas.RestoreState();
}
public virtual void DrawThumb(ICanvas canvas, RectF dirtyRect)
{
const float ThumbSize = 18f;
canvas.SaveState();
var value = (Value / Maximum - Minimum).Clamp(0, 1);
var x = (float)((dirtyRect.Width * value) - (ThumbSize / 2));
if (x <= 0)
x = 0;
if (x >= dirtyRect.Width - ThumbSize)
x = dirtyRect.Width - ThumbSize;
var y = (float)((dirtyRect.Height - ThumbSize) / 2);
if (ThumbPaint != null)
canvas.SetFillPaint(ThumbPaint, dirtyRect);
canvas.FillEllipse(x, y, ThumbSize, ThumbSize);
canvas.RestoreState();
}
}
}

Просмотреть файл

@ -0,0 +1,23 @@
namespace AlohaKit.Extensions
{
public static class NumericExtensions
{
public static double Clamp(this double self, double min, double max)
{
if (max < min)
{
return max;
}
else if (self < min)
{
return min;
}
else if (self > max)
{
return max;
}
return self;
}
}
}