-
Notifications
You must be signed in to change notification settings - Fork 1.9k
[iOS] Fix span Tap gesture on wrapped Label lines in iOS 26+ #34640
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
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
142 changes: 142 additions & 0 deletions
142
src/Controls/tests/TestCases.HostApp/Issues/Issue34504.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,142 @@ | ||
| namespace Maui.Controls.Sample.Issues; | ||
|
|
||
| [Issue(IssueTracker.Github, 34504, "[iOS] Span TapGestureRecognizer does not work on the second line of the span, if the span is wrapped to the next line", PlatformAffected.iOS)] | ||
| public class Issue34504 : NavigationPage | ||
| { | ||
| public Issue34504() : base(new FirstPage()) { } | ||
|
|
||
| // First page mirrors the sandbox MainPage — has the same span content so | ||
| // the layout system is exercised before navigating to the second page. | ||
| class FirstPage : ContentPage | ||
| { | ||
| public FirstPage() | ||
| { | ||
| void OnSpanTapped(object sender, TappedEventArgs e) | ||
| { | ||
| // no-op — first page just needs spans to exist | ||
| } | ||
|
|
||
| var label = BuildSpanLabel(OnSpanTapped); | ||
|
|
||
| var navigateButton = new Button | ||
| { | ||
| Text = "Navigate to Test Page", | ||
| AutomationId = "NavigateButton", | ||
| HorizontalOptions = LayoutOptions.Fill, | ||
| }; | ||
| navigateButton.Clicked += async (s, e) => | ||
| await Navigation.PushAsync(new SecondPage()); | ||
|
|
||
| Content = new VerticalStackLayout | ||
| { | ||
| Padding = new Thickness(30, 0), | ||
| Spacing = 25, | ||
| Children = | ||
| { | ||
| new Label | ||
| { | ||
| Text = "Click the button below to navigate to the test page with wrapped span gestures.", | ||
| FontSize = 14, | ||
| TextColor = Colors.Gray, | ||
| }, | ||
| navigateButton, | ||
| new Border | ||
| { | ||
| StrokeThickness = 2, | ||
| Stroke = Colors.Black, | ||
| Padding = new Thickness(10), | ||
| Content = label, | ||
| }, | ||
| } | ||
| }; | ||
| } | ||
| } | ||
|
|
||
| // Second page mirrors the sandbox TestPage — this is where the bug manifests on iOS 26+. | ||
| public class SecondPage : ContentPage | ||
| { | ||
| public SecondPage() | ||
| { | ||
| var statusLabel = new Label | ||
| { | ||
| AutomationId = "StatusLabel", | ||
| Text = "Tap status will appear here", | ||
| FontSize = 14, | ||
| TextColor = Colors.Black, | ||
| }; | ||
|
|
||
| void OnSpanTapped(object sender, TappedEventArgs e) | ||
| { | ||
| statusLabel.Text = "Success"; | ||
| } | ||
|
|
||
| var spanLabel = BuildSpanLabel(OnSpanTapped); | ||
| spanLabel.AutomationId = "SpanLabel"; | ||
|
|
||
| Content = new ScrollView | ||
| { | ||
| Content = new VerticalStackLayout | ||
| { | ||
| Padding = new Thickness(30, 0), | ||
| Spacing = 25, | ||
| Children = | ||
| { | ||
| new Label | ||
| { | ||
| Text = "iOS TapGesture Issue Demonstration", | ||
| FontSize = 18, | ||
| FontAttributes = FontAttributes.Bold, | ||
| }, | ||
| new Label | ||
| { | ||
| Text = "Tap on the colored text below. On iOS, gestures on wrapped lines may not work.", | ||
| FontSize = 12, | ||
| TextColor = Colors.Gray, | ||
| }, | ||
| new Border | ||
| { | ||
| StrokeThickness = 2, | ||
| Stroke = Colors.Black, | ||
| Padding = new Thickness(10), | ||
| Content = spanLabel, | ||
| }, | ||
| statusLabel, | ||
| } | ||
| } | ||
| }; | ||
| } | ||
| } | ||
|
|
||
| static Label BuildSpanLabel(EventHandler<TappedEventArgs> onTapped) | ||
| { | ||
| Span MakeSpan(string text, Color color) | ||
| { | ||
| var span = new Span | ||
| { | ||
| Text = text, | ||
| TextColor = color, | ||
| TextDecorations = TextDecorations.Underline, | ||
| }; | ||
| var tap = new TapGestureRecognizer(); | ||
| tap.Tapped += onTapped; | ||
| span.GestureRecognizers.Add(tap); | ||
| return span; | ||
| } | ||
|
|
||
| var fs = new FormattedString(); | ||
| fs.Spans.Add(MakeSpan("Hello,This is a test. Hello,This is a test. Hello,This is a test.", Colors.Blue)); | ||
| fs.Spans.Add(MakeSpan("Hello,This is a test1. Hello,This is a test1. Hello,This is a test1.", Colors.Red)); | ||
| fs.Spans.Add(MakeSpan("Hello,This is a test2. Hello,This is a test2. Hello,This is a test2.", Colors.Green)); | ||
| fs.Spans.Add(MakeSpan("Hello,This is a test4. Hello,This is a test4. Hello,This is a test4.", Colors.Orange)); | ||
| fs.Spans.Add(MakeSpan("Hello,This is a test3. Hello,This is a test3. Hello,This is a test3.", Colors.Purple)); | ||
| fs.Spans.Add(new Span { Text = " World!", FontAttributes = FontAttributes.Bold }); | ||
|
|
||
| return new Label | ||
| { | ||
| FormattedText = fs, | ||
| BackgroundColor = Colors.Transparent, | ||
| LineBreakMode = LineBreakMode.WordWrap, | ||
| MaximumWidthRequest = 300, | ||
| }; | ||
| } | ||
| } | ||
34 changes: 34 additions & 0 deletions
34
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34504.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| using NUnit.Framework; | ||
| using UITest.Appium; | ||
| using UITest.Core; | ||
|
|
||
| namespace Microsoft.Maui.TestCases.Tests.Issues; | ||
|
|
||
| public class Issue34504 : _IssuesUITest | ||
| { | ||
| public Issue34504(TestDevice device) : base(device) { } | ||
|
|
||
| public override string Issue => "[iOS] Span TapGestureRecognizer does not work on the second line of the span, if the span is wrapped to the next line"; | ||
|
|
||
| [Test] | ||
| [Category(UITestCategories.Label)] | ||
| // The bug only manifests on iOS 26+ (not Android / Windows / MacCatalyst), | ||
| // but the test is safe to run on all platforms — it will simply pass on unaffected ones. | ||
| public void SpanTapGestureOnSecondLineShouldWork() | ||
| { | ||
| // Navigate to the second page — the bug only reproduces on a pushed page. | ||
| App.WaitForElement("NavigateButton"); | ||
| App.Tap("NavigateButton"); | ||
|
|
||
| var labelRect = App.WaitForElement("SpanLabel").GetRect(); | ||
|
|
||
|
SubhikshaSf4851 marked this conversation as resolved.
|
||
| // Ensure the label wrapped to multiple lines; if it's single-line the tap | ||
| // cannot exercise the second-line bug and the test would be a false-positive. | ||
| Assert.That(labelRect.Height, Is.GreaterThan(40), "SpanLabel must be tall enough to indicate multi-line text before tapping the second line."); | ||
|
|
||
| // Tap near the bottom of the label to hit the second wrapped line of a span. | ||
| App.TapCoordinates(labelRect.X + labelRect.Width / 2, labelRect.Y + labelRect.Height * 0.75f); | ||
|
|
||
| Assert.That(App.WaitForElement("StatusLabel").GetText(), Is.EqualTo("Success")); | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.