Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Handlers] Add IndicatorView handler for iOS and Android #2038

Merged
merged 36 commits into from
Sep 22, 2021
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
5e602e9
Initial work Indicator
rmarinho Aug 5, 2021
de036ce
Make it build
rmarinho Aug 6, 2021
6756094
Try again
rmarinho Aug 6, 2021
6dc75ff
Update to a working version
rmarinho Aug 9, 2021
03f7bf7
Remove commented code
rmarinho Aug 9, 2021
0ddeed0
Move native control measure into OnMeasure override
hartez Aug 9, 2021
fee1de1
Fix IndicatorView measure without changing old method
hartez Aug 9, 2021
f38883a
Add spacing to new Layout
rmarinho Aug 10, 2021
9934eb9
Add more examples to IndicatorView
rmarinho Aug 10, 2021
a607b0f
Fix IndicatorView shapes
rmarinho Aug 10, 2021
166f653
Cleanup
rmarinho Aug 10, 2021
6fc4cbb
Update IIndicatorView
rmarinho Aug 13, 2021
6b14647
Cleanup
rmarinho Aug 13, 2021
6c1141a
refactor MauiPageControl
rmarinho Aug 13, 2021
b935f86
Fix comments
rmarinho Aug 13, 2021
327a17e
Fix sizing
rmarinho Aug 13, 2021
4c60b6b
Add carouselview example cleanup startup page
rmarinho Aug 13, 2021
d38a6e9
Fix extra padding
rmarinho Aug 13, 2021
b922b20
Fix net6 sln null
rmarinho Aug 13, 2021
d8f7332
Fix WINUI indicator
rmarinho Aug 16, 2021
fb70992
Merge branch 'main' into indicator-handler
rmarinho Aug 18, 2021
b60150d
Merge branch 'main' into indicator-handler
rmarinho Aug 30, 2021
44a4f47
Merge branch 'main' into indicator-handler
rmarinho Sep 9, 2021
4f0889a
Merge branch 'main' into indicator-handler
rmarinho Sep 16, 2021
946a1b6
Use IShape
rmarinho Sep 20, 2021
2c61e72
Fix namespace
rmarinho Sep 20, 2021
6e964fa
Add comments to IIndicatorVIew interface
rmarinho Sep 21, 2021
2aa3048
Merge branch 'main' into indicator-handler
rmarinho Sep 21, 2021
67c5e8b
Merge branch 'main' into indicator-handler
rmarinho Sep 21, 2021
46a1d2e
Add Default size
rmarinho Sep 21, 2021
abf8087
[iOS] Some refactor indicatorview iOS
rmarinho Sep 21, 2021
5cc03ea
Remove shapes interfaces
rmarinho Sep 21, 2021
601890f
Use extensions methods for Maximum visible and IsCirceShape
rmarinho Sep 22, 2021
2425196
Use extension method.
rmarinho Sep 22, 2021
786d9f9
try fix extra sizing code
rmarinho Sep 22, 2021
876893b
Remove comment code
rmarinho Sep 22, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/Compatibility/Core/src/AppHostBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ static IAppHostBuilder SetupDefaults(this IAppHostBuilder builder)
handlers.TryAddCompatibilityRenderer(typeof(ListView), typeof(ListViewRenderer));
handlers.TryAddCompatibilityRenderer(typeof(CollectionView), typeof(CollectionViewRenderer));
handlers.TryAddCompatibilityRenderer(typeof(CarouselView), typeof(CarouselViewRenderer));
handlers.TryAddCompatibilityRenderer(typeof(IndicatorView), typeof(IndicatorViewRenderer));
handlers.TryAddCompatibilityRenderer(typeof(Path), typeof(PathRenderer));
handlers.TryAddCompatibilityRenderer(typeof(Ellipse), typeof(EllipseRenderer));
handlers.TryAddCompatibilityRenderer(typeof(Line), typeof(LineRenderer));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<PackageReference Include="Microsoft.Extensions.Logging" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" />
<PackageReference Include="System.Text.Encodings.Web" Version="5.0.1"/>
<PackageReference Include="System.Text.Encodings.Web" Version="5.0.1" />
</ItemGroup>

<ItemGroup>
Expand All @@ -32,6 +32,7 @@
<AndroidResource Remove="Resources\**" />
</ItemGroup>


<Import Project="..\..\..\..\.nuspec\Microsoft.Maui.Controls.MultiTargeting.targets" />

</Project>

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
<views:BasePage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Maui.Controls.Sample.Pages.IndicatorPage"
xmlns:views="clr-namespace:Maui.Controls.Sample.Pages.Base"
Title="IndicatorView">
<views:BasePage.Resources>
<Style x:Key="IndicatorLabelStyle"
TargetType="Label">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="TextColor"
Value="LightGray" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Selected">
<VisualState.Setters>
<Setter Property="TextColor"
Value="Black" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
</views:BasePage.Resources>
<views:BasePage.Content>
<Grid Margin="12">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label
Text="Basic"
Style="{StaticResource Headline}"/>
<IndicatorView Grid.Column="1"
Count="5"
Position="2"
HorizontalOptions="Center" />
<Label
Grid.Row="1"
Text="Colors"
Style="{StaticResource Headline}"/>
<IndicatorView Grid.Row="1" GridLayout.Column="1" Count="5" Position="2" HorizontalOptions="Center" SelectedIndicatorColor="Red" IndicatorColor="Blue" Background="Yellow" />
<Label
Grid.Row="2"
Text="Indicator Shape"
Style="{StaticResource Headline}"/>
<IndicatorView Grid.Row="2" GridLayout.Column="1" Count="5" Position="2" HorizontalOptions="Center" IndicatorsShape="Square"/>
<Label
Grid.Row="3"
Text="Indicator Size"
Style="{StaticResource Headline}"/>
<IndicatorView Grid.Row="3" GridLayout.Column="1" Count="5" Position="2" HorizontalOptions="Center" IndicatorSize="15"/>
<Label
Grid.Row="4"
Text="Indicator HideSingle"
Style="{StaticResource Headline}"/>
<IndicatorView Grid.Row="4" GridLayout.Column="1" Count="1" HorizontalOptions="Center" HideSingle="True"/>
<Label
Grid.Row="5"
Text="Indicator MaximumVisible - 7 of 10"
Style="{StaticResource Headline}"/>
<IndicatorView Grid.Row="5" GridLayout.Column="1" Count="10" Position="3" MaximumVisible="7" HorizontalOptions="Center"/>
<Label
Grid.Row="6"
Text="Indicator Template"
Style="{StaticResource Headline}"/>
<IndicatorView Grid.Row="6" GridLayout.Column="1"
Count="5"
Position="2"
IndicatorColor="Transparent"
SelectedIndicatorColor="Transparent"
HorizontalOptions="Center">
<IndicatorView.IndicatorTemplate>
<DataTemplate>
<Label Text="&#xf30c;" FontFamily="Ionicons" Style="{StaticResource IndicatorLabelStyle}" />
</DataTemplate>
</IndicatorView.IndicatorTemplate>
</IndicatorView>
<Label
Grid.Row="7"
Text="Using with CarouselView"
Style="{StaticResource Headline}" VerticalOptions="Start" />
<StackLayout Grid.Row="7" Grid.Column="1" VerticalOptions="Start" >
<CarouselView IndicatorView="indicatorView" VerticalOptions="Start" HeightRequest="100" Loop="False">
Copy link
Member Author

@rmarinho rmarinho Aug 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CarouselVIew crashes if Loop =true on Android, and doesn't show when Loop=False

<CarouselView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Item 1</x:String>
<x:String>Item 2</x:String>
<x:String>Item 3</x:String>
</x:Array>
</CarouselView.ItemsSource>
<CarouselView.ItemTemplate>
<DataTemplate>
<Grid Background="Pink">
<Label
HorizontalOptions="Center"
VerticalOptions="Center"
FontSize="Large"
Text="{Binding}"/>
</Grid>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
<IndicatorView
Margin="0,20,0,0"
x:Name="indicatorView"
IndicatorColor="LightGray"
SelectedIndicatorColor="DarkGray"
HorizontalOptions="Center" />
</StackLayout>
</Grid>
</views:BasePage.Content>
</views:BasePage>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Graphics;

namespace Maui.Controls.Sample.Pages
{
public partial class IndicatorPage
{
public IndicatorPage()
{
InitializeComponent();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ protected override IEnumerable<SectionModel> CreateItems() => new[]
new SectionModel(typeof(FramePage), "Frame",
"The Frame class derives from ContentView and displays a border, or frame, around its child."),

new SectionModel(typeof(IndicatorViewPage), "IndicatorView",
"IndicatorView displays indicators that represent the number of items in a CarouselView. Set the CarouselView.IndicatorView property to the IndicatorView object to display indicators for the CarouselView."),

new SectionModel(typeof(ListViewPage), "ListView",
"ListView derives from ItemsView and displays a scrollable list of selectable data items."),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ protected override IEnumerable<SectionModel> CreateItems() => new[]

new SectionModel(typeof(TimePickerPage), "TimePicker",
"A view that allows the user to select a time."),

new SectionModel(typeof(IndicatorPage), "IndicatorView",
"IndicatorView displays indicators. It can also represent the number of items in a CarouselView. Set the CarouselView.IndicatorView property to the IndicatorView object to display indicators for the CarouselView."),
};
}
}
13 changes: 13 additions & 0 deletions src/Controls/src/Core/HandlerImpl/IndicatorView.Impl.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Runtime.CompilerServices;
using Microsoft.Maui.Graphics;

namespace Microsoft.Maui.Controls
{
public partial class IndicatorView : ITemplatedIndicatorView
{
Paint IIndicatorView.IndicatorColor => IndicatorColor?.AsPaint();
Paint IIndicatorView.SelectedIndicatorColor => SelectedIndicatorColor?.AsPaint();
IShapeView IIndicatorView.IndicatorsShape => IndicatorsShape == Controls.IndicatorShape.Square ? new Shapes.Rectangle() : new Shapes.Ellipse();
Maui.ILayout ITemplatedIndicatorView.IndicatorsLayoutOverride => (IndicatorTemplate != null) ? IndicatorLayout as Maui.ILayout : null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public static partial class AppHostBuilderExtensions
{ typeof(Shapes.Polyline), typeof(ShapeViewHandler) },
{ typeof(Shapes.Rectangle), typeof(ShapeViewHandler) },
{ typeof(Window), typeof(WindowHandler) },
{ typeof(IndicatorView), typeof(IndicatorViewHandler) },
//{ typeof(NavigationPage), typeof(NavigationPageHandler) },
};

Expand Down
9 changes: 6 additions & 3 deletions src/Controls/src/Core/IndicatorStackLayout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace Microsoft.Maui.Controls
{
internal class IndicatorStackLayout : Compatibility.StackLayout
internal class IndicatorStackLayout : StackLayout
{
IndicatorView _indicatorView;
public IndicatorStackLayout(IndicatorView indicatorView)
Expand Down Expand Up @@ -98,11 +98,14 @@ void ResetIndicatorStylesNonBatch()
var position = _indicatorView.Position;
var selectedIndex = position >= maxVisible ? maxVisible - 1 : position;
bool isSelected = index == selectedIndex;
Children[index].BackgroundColor = isSelected
var visualElement = Children[index] as VisualElement;

visualElement.BackgroundColor = isSelected
? GetColorOrDefault(_indicatorView.SelectedIndicatorColor, Colors.Gray)
: GetColorOrDefault(_indicatorView.IndicatorColor, Colors.Silver);

VisualStateManager.GoToState(Children[index], isSelected

VisualStateManager.GoToState(visualElement, isSelected
? VisualStateManager.CommonStates.Selected
: VisualStateManager.CommonStates.Normal);

Expand Down
55 changes: 47 additions & 8 deletions src/Controls/src/Core/IndicatorView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@
using System.Collections;
using System.Collections.Specialized;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Layouts;

namespace Microsoft.Maui.Controls
{
[ContentProperty(nameof(IndicatorLayout))]
public class IndicatorView : TemplatedView
public partial class IndicatorView : TemplatedView
{
const int DefaultPadding = 4;

public static readonly BindableProperty IndicatorsShapeProperty = BindableProperty.Create(nameof(IndicatorsShape), typeof(IndicatorShape), typeof(IndicatorView), IndicatorShape.Circle);
public static readonly BindableProperty IndicatorsShapeProperty = BindableProperty.Create(nameof(IndicatorsShape), typeof(IndicatorShape), typeof(IndicatorView), Controls.IndicatorShape.Circle);

public static readonly BindableProperty PositionProperty = BindableProperty.Create(nameof(Position), typeof(int), typeof(IndicatorView), default(int), BindingMode.TwoWay);

Expand All @@ -25,9 +26,9 @@ public class IndicatorView : TemplatedView

public static readonly BindableProperty HideSingleProperty = BindableProperty.Create(nameof(HideSingle), typeof(bool), typeof(IndicatorView), true);

public static readonly BindableProperty IndicatorColorProperty = BindableProperty.Create(nameof(IndicatorColor), typeof(Color), typeof(IndicatorView), null);
public static readonly BindableProperty IndicatorColorProperty = BindableProperty.Create(nameof(IndicatorColor), typeof(Color), typeof(IndicatorView), Colors.LightGrey);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding default colors


public static readonly BindableProperty SelectedIndicatorColorProperty = BindableProperty.Create(nameof(SelectedIndicatorColor), typeof(Color), typeof(IndicatorView), null);
public static readonly BindableProperty SelectedIndicatorColorProperty = BindableProperty.Create(nameof(SelectedIndicatorColor), typeof(Color), typeof(IndicatorView), Colors.Black);

public static readonly BindableProperty IndicatorSizeProperty = BindableProperty.Create(nameof(IndicatorSize), typeof(double), typeof(IndicatorView), 6.0);

Expand Down Expand Up @@ -107,25 +108,51 @@ public IEnumerable ItemsSource
set => SetValue(ItemsSourceProperty, value);
}


protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint)
{
var baseRequest = base.OnMeasure(widthConstraint, heightConstraint);

if (IndicatorTemplate != null)
return baseRequest;

var defaultSize = IndicatorSize + DefaultPadding + DefaultPadding + 1;
var items = Count;
var padding = DefaultPadding;
#if __IOS__
padding += 7;
mattleibow marked this conversation as resolved.
Show resolved Hide resolved
#endif
var defaultSize = IndicatorSize + padding + padding;
var items = GetMaximumVisible();

var sizeRequest = new SizeRequest(new Size(items * defaultSize, IndicatorSize), new Size(10, 10));
rmarinho marked this conversation as resolved.
Show resolved Hide resolved

return sizeRequest;
}

protected override Size MeasureOverride(double widthConstraint, double heightConstraint)
{
var margin = Margin;

// Adjust the constraints to account for the margins
widthConstraint -= margin.HorizontalThickness;
heightConstraint -= margin.VerticalThickness;

// Use the old measurement override to figure out the xplat size
var measure = OnMeasure(widthConstraint, heightConstraint).Request;
rmarinho marked this conversation as resolved.
Show resolved Hide resolved

// Make sure the native control gets measured
var nativeMeasure = Handler?.GetDesiredSize(measure.Width, measure.Height);

// Account for the margins when reporting the desired size value
DesiredSize = new Size(measure.Width + margin.HorizontalThickness,
measure.Height + margin.VerticalThickness);

return DesiredSize;
}

static void UpdateIndicatorLayout(IndicatorView indicatorView, object newValue)
{
if (newValue != null)
{
indicatorView.IndicatorLayout = new IndicatorStackLayout(indicatorView);
indicatorView.IndicatorLayout = new IndicatorStackLayout(indicatorView) { Spacing = DefaultPadding };
}
else if (indicatorView.IndicatorLayout == null)
{
Expand Down Expand Up @@ -162,5 +189,17 @@ void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
}
Count = count;
}

int GetMaximumVisible()
rmarinho marked this conversation as resolved.
Show resolved Hide resolved
{
var minValue = Math.Min(MaximumVisible, Count);
var maximumVisible = minValue <= 0 ? 0 : minValue;
bool hideSingle = HideSingle;

if (maximumVisible == 1 && hideSingle)
maximumVisible = 0;

return maximumVisible;
}
}
}
Loading