Merge pull request #26 from jsuarezruiz/segmentedcontrol

Added SegmentedControl
This commit is contained in:
Javier Suárez 2022-07-03 18:58:41 +02:00 коммит произвёл GitHub
Родитель 61f1ffcd8d d8461b6e4d
Коммит b041cb668e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
9 изменённых файлов: 465 добавлений и 8 удалений

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

@ -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>

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

@ -33,8 +33,11 @@ namespace AlohaKit.Gallery.ViewModels
new SectionModel(typeof(ProgressRadialView), "ProgressRadial",
"The ProgressRadial is a control that indicates the progress of a task."),
new SectionModel(typeof(RatingView), "Rating",
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."),
new SectionModel(typeof(SliderView), "Slider",

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

@ -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;
}
}
}