Skip to content

Commit bf347f2

Browse files
kubaflormarinho
authored andcommitted
Templated indicator view - improvements (#25642)
1 parent d8fe1b2 commit bf347f2

File tree

6 files changed

+207
-7
lines changed

6 files changed

+207
-7
lines changed

src/Controls/src/Core/IndicatorView/IndicatorStackLayout.cs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,19 +98,30 @@ internal void ResetIndicatorCount(int oldCount)
9898
}
9999
}
100100

101+
protected override void OnInsert(int index, IView view)
102+
{
103+
base.OnInsert(index, view);
104+
ResetIndicatorStylesNonBatch();
105+
}
106+
107+
protected override void OnRemove(int index, IView view)
108+
{
109+
base.OnRemove(index, view);
110+
ResetIndicatorStylesNonBatch();
111+
}
112+
101113
void ResetIndicatorStylesNonBatch()
102114
{
103115
var indicatorCount = _indicatorView.Count;
104116
var childrenCount = Children.Count;
117+
var maxVisible = _indicatorView.MaximumVisible;
118+
var position = _indicatorView.Position;
119+
var selectedIndex = position >= maxVisible ? maxVisible - 1 : position;
105120

106121
for (int index = 0; index < childrenCount; index++)
107122
{
108-
var maxVisible = _indicatorView.MaximumVisible;
109-
var position = _indicatorView.Position;
110-
var selectedIndex = position >= maxVisible ? maxVisible - 1 : position;
111123
bool isSelected = index == selectedIndex;
112-
var visualElement = Children[index] as VisualElement;
113-
if (visualElement is null)
124+
if (Children[index] is not VisualElement visualElement)
114125
{
115126
return;
116127
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
4+
x:Class="Maui.Controls.Sample.Issues.Issue25598">
5+
<VerticalStackLayout
6+
Padding="30,0"
7+
Spacing="25">
8+
<Button
9+
AutomationId="AddItemButton"
10+
Margin="0,20,0,0"
11+
Command="{Binding AddRandomItemCommand}"
12+
Text="Add Random Item"/>
13+
14+
<Button
15+
AutomationId="RemoveItemButton"
16+
Command="{Binding RemoveCurrentItemCommand}"
17+
CommandParameter="{Binding Source={x:Reference carouselView}, Path=Position}"
18+
Text="Remove Current Item"/>
19+
<Grid
20+
x:Name="cvGrid"
21+
Margin="5,0"
22+
RowDefinitions="Auto,50,Auto"
23+
BackgroundColor="Transparent"
24+
HorizontalOptions="FillAndExpand">
25+
<Label
26+
Grid.Row="0"
27+
FontSize="24"
28+
Text="CarouselView + IndicatorView using DataTemplate!"/>
29+
<CarouselView
30+
x:Name="carouselView"
31+
Grid.Row="1"
32+
HorizontalOptions="FillAndExpand"
33+
IndicatorView="indicatorView"
34+
IsScrollAnimated="True"
35+
ItemsSource="{Binding Items}"
36+
ItemsUpdatingScrollMode="KeepScrollOffset"
37+
VerticalOptions="EndAndExpand"
38+
VerticalScrollBarVisibility="Default">
39+
<CarouselView.ItemTemplate>
40+
<DataTemplate>
41+
<Label
42+
FontSize="18"
43+
HorizontalOptions="Center"
44+
Text="{Binding .}"
45+
VerticalOptions="CenterAndExpand"/>
46+
</DataTemplate>
47+
</CarouselView.ItemTemplate>
48+
</CarouselView>
49+
50+
<IndicatorView
51+
x:Name="indicatorView"
52+
Grid.Row="2"
53+
HorizontalOptions="Center"
54+
IndicatorColor="White"
55+
SelectedIndicatorColor="#2040a0">
56+
<IndicatorView.IndicatorTemplate>
57+
<DataTemplate>
58+
<Border
59+
BackgroundColor="Transparent"
60+
HeightRequest="20"
61+
Stroke="Black"
62+
WidthRequest="20">
63+
<Border.StrokeShape>
64+
<RoundRectangle CornerRadius="5"/>
65+
</Border.StrokeShape>
66+
</Border>
67+
</DataTemplate>
68+
</IndicatorView.IndicatorTemplate>
69+
</IndicatorView>
70+
</Grid>
71+
<Grid
72+
x:Name="cvGrid2"
73+
Margin="5,0"
74+
RowDefinitions="Auto,50,Auto"
75+
BackgroundColor="Transparent"
76+
HorizontalOptions="FillAndExpand">
77+
<Label
78+
Grid.Row="0"
79+
FontSize="24"
80+
Text="CarouselView + IndicatorView NOT USING DataTemplate!"/>
81+
<CarouselView
82+
x:Name="carouselView2"
83+
Grid.Row="1"
84+
HorizontalOptions="FillAndExpand"
85+
IndicatorView="indicatorView2"
86+
IsScrollAnimated="True"
87+
ItemsSource="{Binding Items}"
88+
ItemsUpdatingScrollMode="KeepScrollOffset"
89+
VerticalOptions="EndAndExpand"
90+
VerticalScrollBarVisibility="Default">
91+
<CarouselView.ItemTemplate>
92+
<DataTemplate>
93+
<Label
94+
FontSize="18"
95+
HorizontalOptions="Center"
96+
Text="{Binding .}"
97+
VerticalOptions="CenterAndExpand"/>
98+
</DataTemplate>
99+
</CarouselView.ItemTemplate>
100+
</CarouselView>
101+
102+
<IndicatorView
103+
x:Name="indicatorView2"
104+
Grid.Row="2"
105+
HorizontalOptions="Center"
106+
IndicatorColor="Black"
107+
IndicatorsShape="Square"
108+
SelectedIndicatorColor="#2040a0"/>
109+
</Grid>
110+
</VerticalStackLayout>
111+
</ContentPage>
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System.Collections.ObjectModel;
2+
3+
namespace Maui.Controls.Sample.Issues
4+
{
5+
[Issue(IssueTracker.Github, 25598, "IndicatorView with Template won't show when ItemSource reaches 0 Elements", PlatformAffected.Android)]
6+
public partial class Issue25598 : ContentPage
7+
{
8+
public Issue25598()
9+
{
10+
InitializeComponent();
11+
BindingContext = new Issue25598ViewModel();
12+
}
13+
}
14+
15+
public class Issue25598ViewModel : ViewModel
16+
{
17+
int _lastItemIndex = 3;
18+
19+
private ObservableCollection<string> _items = new() { "Item1", "Item2", "Item3" };
20+
21+
public ObservableCollection<string> Items
22+
{
23+
get => _items;
24+
set
25+
{
26+
if (_items != value)
27+
{
28+
_items = value;
29+
OnPropertyChanged(nameof(Items));
30+
}
31+
}
32+
}
33+
34+
public Command AddRandomItemCommand => new(() => Items.Add($"Item{++_lastItemIndex}"));
35+
36+
public Command RemoveCurrentItemCommand => new Command<int>(index =>
37+
{
38+
if (index >= 0 && index < Items.Count)
39+
Items.RemoveAt(index);
40+
});
41+
}
42+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using NUnit.Framework;
2+
using UITest.Appium;
3+
using UITest.Core;
4+
5+
namespace Microsoft.Maui.TestCases.Tests.Issues
6+
{
7+
public class Issue25598 : _IssuesUITest
8+
{
9+
public Issue25598(TestDevice testDevice) : base(testDevice) { }
10+
11+
public override string Issue => "IndicatorView with Template won't show when ItemSource reaches 0 Elements";
12+
13+
[Test]
14+
[Category(UITestCategories.IndicatorView)]
15+
public void IndicatorWithTemplateShouldBeVisible()
16+
{
17+
App.WaitForElement("RemoveItemButton");
18+
19+
for (int i = 0; i < 3; i++)
20+
App.Click("RemoveItemButton");
21+
22+
for (int i = 0; i < 3; i++)
23+
App.Click("AddItemButton");
24+
25+
VerifyScreenshot();
26+
}
27+
}
28+
}
82.9 KB
Loading

src/Core/src/Platform/Android/MauiPageControl.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ public class MauiPageControl : LinearLayout
2020

2121
IIndicatorView? _indicatorView;
2222

23+
bool _isTemplateIndicator;
24+
2325
public MauiPageControl(Context? context) : base(context)
2426
{
2527
}
@@ -37,6 +39,7 @@ public void ResetIndicators()
3739
{
3840
_pageShape = null;
3941
_currentPageShape = null;
42+
_isTemplateIndicator = false;
4043

4144
if ((_indicatorView as ITemplatedIndicatorView)?.IndicatorsLayoutOverride == null)
4245
UpdateShapes();
@@ -63,7 +66,7 @@ public void UpdatePosition()
6366

6467
public void UpdateIndicatorCount()
6568
{
66-
if (_indicatorView == null || Context == null)
69+
if (_indicatorView == null || Context == null || _isTemplateIndicator)
6770
return;
6871

6972
var index = GetIndexFromPosition();
@@ -107,6 +110,7 @@ void UpdateIndicatorTemplate(ILayout? layout)
107110
return;
108111

109112
AView? handler = layout.ToPlatform(_indicatorView.Handler.MauiContext);
113+
_isTemplateIndicator = true;
110114

111115
RemoveAllViews();
112116
AddView(handler);
@@ -170,7 +174,11 @@ int GetIndexFromPosition()
170174

171175
void RemoveViews(int startAt)
172176
{
173-
for (int i = startAt; i < ChildCount; i++)
177+
if (_isTemplateIndicator)
178+
return;
179+
180+
var count = ChildCount;
181+
for (int i = startAt; i < count; i++)
174182
{
175183
var imageView = GetChildAt(ChildCount - 1);
176184
imageView?.SetOnClickListener(null);

0 commit comments

Comments
 (0)