Merge pull request #26 from jsuarezruiz/segmentedcontrol
Added SegmentedControl
This commit is contained in:
Коммит
b041cb668e
|
@ -51,7 +51,7 @@
|
|||
|
||||
<ItemGroup Condition="$(TargetFramework.Contains('-windows'))">
|
||||
<!-- Required - WinUI does not yet have buildTransitive for everything -->
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.0.3" />
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.Graphics.Win2D" Version="1.0.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -34,6 +34,9 @@ namespace AlohaKit.Gallery.ViewModels
|
|||
new SectionModel(typeof(ProgressRadialView), "ProgressRadial",
|
||||
"The ProgressRadial is a control that indicates the progress of a task."),
|
||||
|
||||
new SectionModel(typeof(SegmentedControlView), "SegmentedControl",
|
||||
"The SegmentedControl provides a simple way to choose from a linear set of two or more segments."),
|
||||
|
||||
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."),
|
||||
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
<?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.SegmentedControlView"
|
||||
xmlns:controls="clr-namespace:AlohaKit.Controls;assembly=AlohaKit"
|
||||
Title="SegmentedControl">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<!-- DESCRIPTION -->
|
||||
<StackLayout
|
||||
Style="{StaticResource SectionContainerStyle}">
|
||||
<Label
|
||||
Text="The SegmentedControl provides a simple way to choose from a linear set of two or more segments."/>
|
||||
</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="- Populates the segments from a collection of strings."/>
|
||||
<Label
|
||||
Text="- Supports customizing text and other UI elements."/>
|
||||
<Label
|
||||
Text="- Active segment can be customized."/>
|
||||
<Label
|
||||
Text="- Available events and commands to detect the change of the selected segment."/>
|
||||
</StackLayout>
|
||||
<controls:SegmentedControl
|
||||
Grid.Row="3"
|
||||
Background="#F9F8FF"
|
||||
ActiveBackground="#bf5f82"
|
||||
TextColor="Black"
|
||||
ActiveTextColor="White"
|
||||
Margin="12">
|
||||
<controls:SegmentedControl.ItemsSource>
|
||||
<x:Array Type="{x:Type x:String}">
|
||||
<x:String>Tab 1</x:String>
|
||||
<x:String>Tab 2</x:String>
|
||||
<x:String>Tab 3</x:String>
|
||||
</x:Array>
|
||||
</controls:SegmentedControl.ItemsSource>
|
||||
</controls:SegmentedControl>
|
||||
</Grid>
|
||||
</ContentPage>
|
|
@ -0,0 +1,9 @@
|
|||
namespace AlohaKit.Gallery;
|
||||
|
||||
public partial class SegmentedControlView : ContentPage
|
||||
{
|
||||
public SegmentedControlView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net6.0;net6.0-android;net6.0-ios;net6.0-maccatalyst</TargetFrameworks>
|
||||
|
@ -20,12 +20,8 @@
|
|||
<Folder Include="Platforms\iOS\" />
|
||||
<Folder Include="Platforms\MacCatalyst\" />
|
||||
<Folder Include="Platforms\Windows\" />
|
||||
<Folder Include="Controls\ProgressBar\Drawable\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Controls\ProgressBar\Drawable\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\icon.png">
|
||||
<Pack>True</Pack>
|
||||
|
|
|
@ -0,0 +1,272 @@
|
|||
using AlohaKit.Extensions;
|
||||
using System.Collections;
|
||||
|
||||
namespace AlohaKit.Controls
|
||||
{
|
||||
public class SegmentedControl : GraphicsView
|
||||
{
|
||||
public SegmentedControl()
|
||||
{
|
||||
HeightRequest = 48;
|
||||
|
||||
Drawable = SegmentedControlDrawable = new SegmentedControlDrawable();
|
||||
|
||||
StartInteraction += OnSegmentedControlStartInteraction;
|
||||
}
|
||||
|
||||
public SegmentedControlDrawable SegmentedControlDrawable { get; set; }
|
||||
|
||||
public static readonly new BindableProperty BackgroundProperty =
|
||||
BindableProperty.Create(nameof(Background), typeof(Brush), typeof(SegmentedControl), null,
|
||||
propertyChanged: (bindableObject, oldValue, newValue) =>
|
||||
{
|
||||
if (newValue != null && bindableObject is SegmentedControl segmentedControl)
|
||||
{
|
||||
segmentedControl.UpdateBackground();
|
||||
}
|
||||
});
|
||||
|
||||
public new Brush Background
|
||||
{
|
||||
get => (Brush)GetValue(BackgroundProperty);
|
||||
set => SetValue(BackgroundProperty, value);
|
||||
}
|
||||
|
||||
public static readonly BindableProperty ActiveBackgroundProperty =
|
||||
BindableProperty.Create(nameof(ActiveBackground), typeof(Brush), typeof(SegmentedControl), null,
|
||||
propertyChanged: (bindableObject, oldValue, newValue) =>
|
||||
{
|
||||
if (newValue != null && bindableObject is SegmentedControl segmentedControl)
|
||||
{
|
||||
segmentedControl.UpdateActiveBackground();
|
||||
}
|
||||
});
|
||||
|
||||
public Brush ActiveBackground
|
||||
{
|
||||
get => (Brush)GetValue(ActiveBackgroundProperty);
|
||||
set => SetValue(ActiveBackgroundProperty, value);
|
||||
}
|
||||
|
||||
public static readonly BindableProperty ItemsSourceProperty =
|
||||
BindableProperty.Create(nameof(ItemsSource), typeof(IEnumerable), typeof(SegmentedControl), null,
|
||||
propertyChanged: (bindableObject, oldValue, newValue) =>
|
||||
{
|
||||
if (newValue != null && bindableObject is SegmentedControl segmentedControl)
|
||||
{
|
||||
segmentedControl.UpdateItemsSource();
|
||||
}
|
||||
});
|
||||
|
||||
public IEnumerable ItemsSource
|
||||
{
|
||||
get => (IEnumerable)GetValue(ItemsSourceProperty);
|
||||
set => SetValue(ItemsSourceProperty, value);
|
||||
}
|
||||
|
||||
public static readonly BindableProperty SelectedIndexProperty =
|
||||
BindableProperty.Create(nameof(SelectedIndex), typeof(int), typeof(SegmentedControl), 0,
|
||||
propertyChanged: (bindableObject, oldValue, newValue) =>
|
||||
{
|
||||
if (newValue != null && bindableObject is SegmentedControl segmentedControl)
|
||||
{
|
||||
segmentedControl.UpdateSelectedIndex();
|
||||
}
|
||||
});
|
||||
|
||||
public int SelectedIndex
|
||||
{
|
||||
get => (int)GetValue(SelectedIndexProperty);
|
||||
set => SetValue(SelectedIndexProperty, value);
|
||||
}
|
||||
|
||||
public static readonly BindableProperty TextColorProperty =
|
||||
BindableProperty.Create(nameof(TextColor), typeof(Color), typeof(SegmentedControl), null,
|
||||
propertyChanged: (bindableObject, oldValue, newValue) =>
|
||||
{
|
||||
if (newValue != null && bindableObject is SegmentedControl segmentedControl)
|
||||
{
|
||||
segmentedControl.UpdateTextColor();
|
||||
}
|
||||
});
|
||||
|
||||
public Color TextColor
|
||||
{
|
||||
get { return (Color)GetValue(TextColorProperty); }
|
||||
set { SetValue(TextColorProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly BindableProperty ActiveTextColorProperty =
|
||||
BindableProperty.Create(nameof(ActiveTextColor), typeof(Color), typeof(SegmentedControl), null,
|
||||
propertyChanged: (bindableObject, oldValue, newValue) =>
|
||||
{
|
||||
if (newValue != null && bindableObject is SegmentedControl segmentedControl)
|
||||
{
|
||||
segmentedControl.UpdateActiveTextColor();
|
||||
}
|
||||
});
|
||||
|
||||
public Color ActiveTextColor
|
||||
{
|
||||
get { return (Color)GetValue(ActiveTextColorProperty); }
|
||||
set { SetValue(ActiveTextColorProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly BindableProperty FontSizeProperty =
|
||||
BindableProperty.Create(nameof(FontSize), typeof(double), typeof(SegmentedControl), 18.0d,
|
||||
propertyChanged: (bindableObject, oldValue, newValue) =>
|
||||
{
|
||||
if (newValue != null && bindableObject is SegmentedControl segmentedControl)
|
||||
{
|
||||
segmentedControl.UpdateFontSize();
|
||||
}
|
||||
});
|
||||
|
||||
public double FontSize
|
||||
{
|
||||
get { return (double)GetValue(FontSizeProperty); }
|
||||
set { SetValue(FontSizeProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly BindableProperty ActiveFontSizeProperty =
|
||||
BindableProperty.Create(nameof(ActiveFontSize), typeof(double), typeof(SegmentedControl), 20.0d,
|
||||
propertyChanged: (bindableObject, oldValue, newValue) =>
|
||||
{
|
||||
if (newValue != null && bindableObject is SegmentedControl segmentedControl)
|
||||
{
|
||||
segmentedControl.UpdateActiveFontSize();
|
||||
}
|
||||
});
|
||||
|
||||
public double ActiveFontSize
|
||||
{
|
||||
get { return (double)GetValue(ActiveFontSizeProperty); }
|
||||
set { SetValue(ActiveFontSizeProperty, value); }
|
||||
}
|
||||
|
||||
public event EventHandler<SelectedIndexEventArgs> SelectedIndexChanged;
|
||||
|
||||
protected override void OnParentSet()
|
||||
{
|
||||
base.OnParentSet();
|
||||
|
||||
if (Parent != null)
|
||||
{
|
||||
UpdateBackground();
|
||||
UpdateActiveBackground();
|
||||
UpdateItemsSource();
|
||||
UpdateSelectedIndex();
|
||||
UpdateTextColor();
|
||||
UpdateActiveTextColor();
|
||||
UpdateFontSize();
|
||||
UpdateActiveFontSize();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnSizeAllocated(double width, double height)
|
||||
{
|
||||
base.OnSizeAllocated(width, height);
|
||||
|
||||
WidthRequest = width;
|
||||
HeightRequest = height;
|
||||
}
|
||||
|
||||
void UpdateBackground()
|
||||
{
|
||||
if (SegmentedControlDrawable == null)
|
||||
return;
|
||||
|
||||
SegmentedControlDrawable.BackgroundPaint = Background;
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
void UpdateActiveBackground()
|
||||
{
|
||||
if (SegmentedControlDrawable == null)
|
||||
return;
|
||||
|
||||
SegmentedControlDrawable.ActiveBackgroundPaint = ActiveBackground;
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
void UpdateItemsSource()
|
||||
{
|
||||
if (SegmentedControlDrawable == null)
|
||||
return;
|
||||
|
||||
SegmentedControlDrawable.ItemsSource = ItemsSource;
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
void UpdateSelectedIndex()
|
||||
{
|
||||
if (SegmentedControlDrawable == null)
|
||||
return;
|
||||
|
||||
SegmentedControlDrawable.SelectedIndex = SelectedIndex;
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
void UpdateTextColor()
|
||||
{
|
||||
if (SegmentedControlDrawable == null)
|
||||
return;
|
||||
|
||||
SegmentedControlDrawable.TextColor = TextColor;
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
void UpdateActiveTextColor()
|
||||
{
|
||||
if (SegmentedControlDrawable == null)
|
||||
return;
|
||||
|
||||
SegmentedControlDrawable.ActiveTextColor = ActiveTextColor;
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
void UpdateFontSize()
|
||||
{
|
||||
if (SegmentedControlDrawable == null)
|
||||
return;
|
||||
|
||||
SegmentedControlDrawable.FontSize = (float)FontSize;
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
void UpdateActiveFontSize()
|
||||
{
|
||||
if (SegmentedControlDrawable == null)
|
||||
return;
|
||||
|
||||
SegmentedControlDrawable.ActiveFontSize = (float)ActiveFontSize;
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
void OnSegmentedControlStartInteraction(object sender, TouchEventArgs e)
|
||||
{
|
||||
float positionX = e.Touches[0].X;
|
||||
var tabItemWidth = Width / ItemsSource.Count();
|
||||
|
||||
for (int i = 0; i < ItemsSource.Count(); i++)
|
||||
{
|
||||
float tabPositionX = (float)(i * tabItemWidth);
|
||||
|
||||
if (positionX >= tabPositionX
|
||||
&& positionX <= (tabPositionX + tabItemWidth))
|
||||
{
|
||||
SelectedIndex = i;
|
||||
SelectedIndexChanged?.Invoke(this, new SelectedIndexEventArgs(SelectedIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
using AlohaKit.Extensions;
|
||||
using System.Collections;
|
||||
|
||||
namespace AlohaKit.Controls
|
||||
{
|
||||
public class SegmentedControlDrawable : IDrawable
|
||||
{
|
||||
public Paint BackgroundPaint { get; set; }
|
||||
public Paint ActiveBackgroundPaint { get; set; }
|
||||
public IEnumerable ItemsSource { get; set; }
|
||||
public int SelectedIndex { get; set; }
|
||||
public Color TextColor { get; set; }
|
||||
public Color ActiveTextColor { get; set; }
|
||||
public float FontSize { get; set; }
|
||||
public float ActiveFontSize { get; set; }
|
||||
|
||||
public void Draw(ICanvas canvas, RectF dirtyRect)
|
||||
{
|
||||
DrawBackground(canvas, dirtyRect);
|
||||
DrawActiveTab(canvas, dirtyRect);
|
||||
DrawTabs(canvas, dirtyRect);
|
||||
}
|
||||
|
||||
void DrawBackground(ICanvas canvas, RectF dirtyRect)
|
||||
{
|
||||
canvas.SaveState();
|
||||
|
||||
if (BackgroundPaint != null)
|
||||
{
|
||||
canvas.SetFillPaint(BackgroundPaint, dirtyRect);
|
||||
|
||||
float tabItemRadius = dirtyRect.Height / 2;
|
||||
canvas.FillRoundedRectangle(0, 0, dirtyRect.Width, dirtyRect.Height, tabItemRadius);
|
||||
}
|
||||
|
||||
canvas.RestoreState();
|
||||
}
|
||||
|
||||
void DrawActiveTab(ICanvas canvas, RectF dirtyRect)
|
||||
{
|
||||
canvas.SaveState();
|
||||
|
||||
if (ActiveBackgroundPaint != null)
|
||||
{
|
||||
var tabItemWidth = dirtyRect.Width / ItemsSource.Count();
|
||||
|
||||
float tabItemRadius = dirtyRect.Height / 2;
|
||||
|
||||
canvas.SetFillPaint(ActiveBackgroundPaint, dirtyRect);
|
||||
|
||||
canvas.FillRoundedRectangle(SelectedIndex * tabItemWidth, 0, tabItemWidth, dirtyRect.Height, tabItemRadius);
|
||||
}
|
||||
|
||||
canvas.RestoreState();
|
||||
}
|
||||
|
||||
void DrawTabs(ICanvas canvas, RectF dirtyRect)
|
||||
{
|
||||
var tabItemWidth = dirtyRect.Width / ItemsSource.Count();
|
||||
|
||||
for (int i = 0; i < ItemsSource.Count(); i++)
|
||||
{
|
||||
string title = (string)ItemsSource.ElementAt(i);
|
||||
|
||||
var x = tabItemWidth * i;
|
||||
|
||||
canvas.FontSize = (i == SelectedIndex) ? ActiveFontSize : FontSize;
|
||||
canvas.FontColor = (i == SelectedIndex) ? ActiveTextColor : TextColor;
|
||||
|
||||
canvas.DrawString(title, x, 0, tabItemWidth, dirtyRect.Height, HorizontalAlignment.Center, VerticalAlignment.Center, TextFlow.ClipBounds, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
namespace AlohaKit.Controls
|
||||
{
|
||||
public class SelectedIndexEventArgs : EventArgs
|
||||
{
|
||||
public SelectedIndexEventArgs(int selectedIndex)
|
||||
{
|
||||
SelectedIndex = selectedIndex;
|
||||
}
|
||||
|
||||
public int SelectedIndex { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
using System.Collections;
|
||||
|
||||
namespace AlohaKit.Extensions
|
||||
{
|
||||
public static class IEnumerableExtensions
|
||||
{
|
||||
public static int Count(this IEnumerable source)
|
||||
{
|
||||
var enumerator = source.GetEnumerator();
|
||||
|
||||
int count = 0;
|
||||
|
||||
while (enumerator.MoveNext())
|
||||
count++;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
public static object ElementAt(this IEnumerable source, int index)
|
||||
{
|
||||
int retval = -1;
|
||||
var enumerator = source.GetEnumerator();
|
||||
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
retval += 1;
|
||||
|
||||
if (retval.Equals(index))
|
||||
{
|
||||
return enumerator.Current;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче