-
Notifications
You must be signed in to change notification settings - Fork 2k
[iOS & macOS] Fixed IndicatorView square shape does not update on load or dynamically #31291
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
Changes from all commits
1ff9c3b
3a8865c
88dff43
fd9e1ff
544c099
a31f90a
9d6a6bf
4ca22f8
29502ff
0e73bb5
e12ca60
ec7c27e
3a78399
3ea5b2e
45396c2
fa7c0e4
1cd1bf8
27c343c
068614c
129ae7c
46e9c0a
f714ffd
64f1928
c8b9aed
07970a2
2c76f87
c982508
afbd3a7
6fc105a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| namespace Maui.Controls.Sample.Issues; | ||
|
|
||
| [Issue(IssueTracker.Github, 31065, "IndicatorView square shape does not update on load or dynamically", PlatformAffected.iOS | PlatformAffected.macOS)] | ||
| public class Issue31065 : ContentPage | ||
| { | ||
| IndicatorView _indicator; | ||
| public Issue31065() | ||
| { | ||
| var carousel = new CarouselView | ||
| { | ||
| ItemsSource = new[] { "Item 1", "Item 2", "Item 3" }, | ||
| HeightRequest = 250, | ||
| }; | ||
|
|
||
| _indicator = new IndicatorView | ||
| { | ||
| IndicatorsShape = IndicatorShape.Square, | ||
| SelectedIndicatorColor = Colors.Blue, | ||
| IndicatorSize = 30 | ||
| }; | ||
|
|
||
| Button button = new Button | ||
| { | ||
| Text = "Change indicator shape", | ||
| HorizontalOptions = LayoutOptions.Center, | ||
| AutomationId = "ChangeIndicatorShapeButton", | ||
| Margin = new Thickness(0, 20, 0, 0) | ||
| }; | ||
|
|
||
| button.Command = new Command(() => | ||
| { | ||
| if (_indicator.IndicatorsShape == IndicatorShape.Square) | ||
| { | ||
| _indicator.IndicatorsShape = IndicatorShape.Circle; | ||
| } | ||
| else | ||
| { | ||
| _indicator.IndicatorsShape = IndicatorShape.Square; | ||
| } | ||
| }); | ||
|
|
||
| carousel.IndicatorView = _indicator; | ||
|
|
||
| Content = new VerticalStackLayout | ||
| { | ||
| Children = | ||
| { | ||
| carousel, | ||
| _indicator, | ||
| button | ||
| } | ||
| }; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| using NUnit.Framework; | ||
| using UITest.Appium; | ||
| using UITest.Core; | ||
|
|
||
| namespace Microsoft.Maui.TestCases.Tests.Issues; | ||
|
|
||
| public class Issue31065 : _IssuesUITest | ||
| { | ||
| public override string Issue => "IndicatorView square shape does not update on load or dynamically"; | ||
|
|
||
| public Issue31065(TestDevice device) : base(device) | ||
| { } | ||
|
|
||
| [Test, Order(0)] | ||
| [Category(UITestCategories.IndicatorView)] | ||
| public void UpdateIndicatorViewSquareShape() | ||
| { | ||
| App.WaitForElement("ChangeIndicatorShapeButton"); | ||
| VerifyScreenshot("IndicatorViewSquareShape"); | ||
| } | ||
|
|
||
| [Test, Order(1)] | ||
| [Category(UITestCategories.IndicatorView)] | ||
| public void UpdateIndicatorViewCircleShape() | ||
| { | ||
| App.Tap("ChangeIndicatorShapeButton"); | ||
| VerifyScreenshot("IndicatorViewCircleShape"); | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,7 +10,8 @@ public class MauiPageControl : UIPageControl, IUIViewLifeCycleEvents | |
| { | ||
| const int DefaultIndicatorSize = 6; | ||
| const double IndicatorSizeTolerance = 0.001; | ||
|
|
||
| const string SquareSymbol = "squareshape.fill"; | ||
| const string CircleSymbol = "circlebadge.fill"; | ||
| WeakReference<IIndicatorView>? _indicatorView; | ||
| bool _updatingPosition; | ||
| double _lastAppliedIndicatorSize = -1; | ||
|
|
@@ -56,11 +57,10 @@ public override void LayoutSubviews() | |
| return; | ||
|
|
||
| UpdateIndicatorSize(); | ||
|
|
||
| if (!IsSquare) | ||
| return; | ||
|
|
||
| UpdateSquareShape(); | ||
| if (_indicatorView?.TryGetTarget(out var indicatorView) == true && (indicatorView as ITemplatedIndicatorView)?.IndicatorsLayoutOverride == null) | ||
| { | ||
| UpdateIndicatorShape(); | ||
| } | ||
| } | ||
|
|
||
| public void UpdateIndicatorSize() | ||
|
|
@@ -107,9 +107,9 @@ public void UpdateIndicatorCount() | |
| UpdatePosition(); | ||
| } | ||
|
|
||
| void UpdateSquareShape() | ||
| void UpdateIndicatorShape() | ||
| { | ||
| if (!(OperatingSystem.IsIOSVersionAtLeast(14) || OperatingSystem.IsTvOSVersionAtLeast(14))) | ||
| if (!(OperatingSystem.IsIOSVersionAtLeast(14) || OperatingSystem.IsTvOSVersionAtLeast(14) || OperatingSystem.IsMacCatalystVersionAtLeast(14))) | ||
| { | ||
| UpdateCornerRadius(); | ||
| return; | ||
|
|
@@ -118,20 +118,34 @@ void UpdateSquareShape() | |
| var uiPageControlContentView = Subviews[0]; | ||
| if (uiPageControlContentView.Subviews.Length > 0) | ||
| { | ||
| var uiPageControlIndicatorContentView = uiPageControlContentView.Subviews[0]; | ||
| foreach (var uiPageControlIndicatorContentView in uiPageControlContentView.Subviews) | ||
| { | ||
| SetIndicatorShape(uiPageControlIndicatorContentView, IsSquare); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| foreach (var view in uiPageControlIndicatorContentView.Subviews) | ||
| // Recursively find UIImageView and set its image | ||
| static void SetIndicatorShape(UIView view, bool isSquare) | ||
| { | ||
| if (view is UIImageView imageView) | ||
| { | ||
| if (OperatingSystem.IsIOSVersionAtLeast(13) || OperatingSystem.IsTvOSVersionAtLeast(13) || OperatingSystem.IsMacCatalystVersionAtLeast(13)) | ||
| { | ||
| if (view is UIImageView imageview) | ||
| { | ||
| if (OperatingSystem.IsIOSVersionAtLeast(13) || OperatingSystem.IsTvOSVersionAtLeast(13)) | ||
| imageview.Image = UIImage.GetSystemImage("squareshape.fill"); | ||
| var frame = imageview.Frame; | ||
| //the square shape is not the same size as the circle so we might need to correct the frame | ||
| imageview.Frame = new CGRect(frame.X - 6, frame.Y, frame.Width, frame.Height); | ||
|
Tamilarasan-Paranthaman marked this conversation as resolved.
|
||
| } | ||
| imageView.Image = UIImage.GetSystemImage(isSquare ? SquareSymbol : CircleSymbol); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [major] iOS/MacCatalyst Platform — This now replaces every non-templated circle IndicatorView's native
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The recommended change causes a loop when updating the indicator shape dynamically. |
||
| return; | ||
| } | ||
| } | ||
|
|
||
| if (view.Subviews is null || view.Subviews.Length == 0) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| foreach (var child in view.Subviews) | ||
|
Tamilarasan-Paranthaman marked this conversation as resolved.
|
||
| { | ||
| SetIndicatorShape(child, isSquare); | ||
| } | ||
| } | ||
|
|
||
| void UpdateCornerRadius() | ||
|
|
@@ -150,7 +164,7 @@ void MauiPageControlValueChanged(object? sender, System.EventArgs e) | |
| indicatorView.Position = (int)CurrentPage; | ||
| //if we are iOS13 or lower and we are using a Square shape | ||
| //we need to update the CornerRadius of the new shape. | ||
| if (IsSquare && !(OperatingSystem.IsIOSVersionAtLeast(14) || OperatingSystem.IsTvOSVersionAtLeast(14))) | ||
| if (IsSquare && !(OperatingSystem.IsIOSVersionAtLeast(14) || OperatingSystem.IsTvOSVersionAtLeast(14) || OperatingSystem.IsMacCatalystVersionAtLeast(14))) | ||
| LayoutSubviews(); | ||
|
|
||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.