Skip to content

[iOS] Fix span Tap gesture on wrapped Label lines in iOS 26+#34640

Merged
kubaflo merged 4 commits into
dotnet:inflight/currentfrom
SubhikshaSf4851:Fix-34504
Apr 18, 2026
Merged

[iOS] Fix span Tap gesture on wrapped Label lines in iOS 26+#34640
kubaflo merged 4 commits into
dotnet:inflight/currentfrom
SubhikshaSf4851:Fix-34504

Conversation

@SubhikshaSf4851
Copy link
Copy Markdown
Contributor

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment whether this change resolves your issue. Thank you!

Root Cause :

On iOS 26+, UILabel layout isn’t finalized when span positions are calculated, so gesture hit areas are computed too early—leading to incorrect tap detection, especially for wrapped lines after navigation.

Description of Change :

  • Updated Label.iOS.cs to detect when the native UILabel bounds are not yet finalized during ArrangeOverride (on iOS/MacCatalyst 26+), and defer span position recalculation to the next main run loop iteration to ensure correct gesture hit-testing. [1] [2]

Testing and Reproduction:

  • Added a new issue reproduction page (Issue34504) to the test cases app, which sets up navigation and span labels to exercise the layout and gesture recognition scenario.
  • Introduced an automated UI test (Issue34504.cs in shared tests) that navigates to the test page and verifies that tapping on a wrapped span line successfully triggers the gesture.

Issues Fixed

Fixes #34504

Tested the behavior in the following platforms

  • Windows
  • Android
  • iOS
  • Mac
Before Issue Fix After Issue Fix
BeforeFixiOS34054.mov
AfterFix34054.mov

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 25, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 34640

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 34640"

@dotnet-policy-service dotnet-policy-service Bot added community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration labels Mar 25, 2026
@sheiksyedm sheiksyedm marked this pull request as ready for review March 26, 2026 10:37
Copilot AI review requested due to automatic review settings March 26, 2026 10:37
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes incorrect hit-testing for Span TapGestureRecognizer on wrapped Label lines on iOS 26+ by deferring span-region recalculation until the native UILabel bounds have been finalized, and adds a HostApp repro + automated UI test for issue #34504.

Changes:

  • Update iOS Label.ArrangeOverride to defer RecalculateSpanPositions when UILabel.Bounds is still unset on iOS/MacCatalyst 26+.
  • Add a new HostApp issue page (Issue34504) reproducing the NavigationPage + wrapped-span tap scenario.
  • Add a new Appium/NUnit UI test (Issue34504) validating taps on wrapped span lines after navigation.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
src/Controls/src/Core/Label/Label.iOS.cs Defers span-region recalculation on iOS/MacCatalyst 26+ when UILabel.Bounds isn’t finalized yet.
src/Controls/tests/TestCases.HostApp/Issues/Issue34504.cs Adds a two-page NavigationPage-based repro with formatted spans and a success indicator.
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34504.cs Adds an automated UI test that navigates and taps within the label to trigger a span tap.

Comment thread src/Controls/src/Core/Label/Label.iOS.cs Outdated
Comment thread src/Controls/src/Core/Label/Label.iOS.cs Outdated
Comment thread src/Controls/tests/TestCases.HostApp/Issues/Issue34504.cs
@MauiBot MauiBot added s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) s/agent-review-incomplete and removed s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-review-incomplete labels Mar 27, 2026
Copy link
Copy Markdown
Contributor

@kubaflo kubaflo left a comment

Choose a reason for hiding this comment

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

Looks like the test couldn't catch a bug before fix

@SubhikshaSf4851
Copy link
Copy Markdown
Contributor Author

@kubaflo The test was executed locally and failed on iOS 26 as expected without the fix. The test results for iOS 18 and iOS 26, both with and without the fix, have been shared below. This issue is specific to iOS 26 and does not reproduce on iOS 18, which is why the test passes on iOS 18 with and without the fix.

iOS 18 version test results :

Without Fix With Fix
WithoutFix18versioniOS WithFix18versioniOS

iOS 26 version test results :

Without Fix With Fix
WithoutFix26versioniOS WithFix26versioniOS

@MauiBot
Copy link
Copy Markdown
Collaborator

MauiBot commented Apr 18, 2026

🚦 Gate — Test Before and After Fix

👋 @SubhikshaSf4851 — new gate results are available. Please review the latest session below.

🚦 Gate Sessioncd50119 · Updated the recommended changes · 2026-04-18 13:45 UTC

Gate Result: ❌ FAILED

Platform: IOS · Base: main · Merge base: eb0b82fe

Test Without Fix (expect FAIL) With Fix (expect PASS)
🖥️ Issue34504 Issue34504 ❌ PASS — 221s ✅ PASS — 92s
🔴 Without fix — 🖥️ Issue34504: PASS ❌ · 221s
  Determining projects to restore...
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/BindingSourceGen/Controls.BindingSourceGen.csproj (in 464 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 558 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Essentials/src/Essentials.csproj (in 7.3 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Core/src/Core.csproj (in 17.41 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/Foldable/src/Controls.Foldable.csproj (in 17.46 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Xaml/Controls.Xaml.csproj (in 17.44 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj (in 17.42 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 17.49 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/BlazorWebView/src/Maui/Microsoft.AspNetCore.Components.WebView.Maui.csproj (in 17.51 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Core/maps/src/Maps.csproj (in 17.52 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/Maps/src/Controls.Maps.csproj (in 17.52 sec).
/Users/cloudtest/vss/_work/1/s/.dotnet/packs/Microsoft.iOS.Sdk.net10.0_26.0/26.0.11017/targets/Xamarin.Shared.Sdk.targets(309,3): warning : RuntimeIdentifier was set on the command line, and will override the value for RuntimeIdentifiers set in the project file. [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-ios]
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.13876771
  Graphics -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Graphics/Debug/net10.0-ios26.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.13876771
  Essentials -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Essentials/Debug/net10.0-ios26.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.13876771
  Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Core/Debug/net10.0-ios26.0/Microsoft.Maui.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.13876771
  Controls.BindingSourceGen -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  Maps -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Maps/Debug/net10.0-ios26.0/Microsoft.Maui.Maps.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.13876771
  Controls.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.13876771
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.13876771
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.13876771
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.13876771
  Controls.Xaml -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Xaml.dll
  Microsoft.AspNetCore.Components.WebView.Maui -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-ios26.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
  Controls.Foldable -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Foldable.dll
  Controls.Maps -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Maps.dll
  Detected signing identity:
    Code Signing Key: "" (-)
    Provisioning Profile: "" () - no entitlements
    Bundle Id: com.microsoft.maui.uitests
    App Id: com.microsoft.maui.uitests
  Controls.TestCases.HostApp -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-ios/iossimulator-arm64/Controls.TestCases.HostApp.dll
  Optimizing assemblies for size may change the behavior of the app. Be sure to test after publishing. See: https://aka.ms/dotnet-illink
  Optimizing assemblies for size. This process might take a while.

Build succeeded.

/Users/cloudtest/vss/_work/1/s/.dotnet/packs/Microsoft.iOS.Sdk.net10.0_26.0/26.0.11017/targets/Xamarin.Shared.Sdk.targets(309,3): warning : RuntimeIdentifier was set on the command line, and will override the value for RuntimeIdentifiers set in the project file. [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-ios]
    1 Warning(s)
    0 Error(s)

Time Elapsed 00:01:42.75
  Determining projects to restore...
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/BindingSourceGen/Controls.BindingSourceGen.csproj (in 676 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 680 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/UITest.Core/UITest.Core.csproj (in 676 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/VisualTestUtils/VisualTestUtils.csproj (in 676 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/tests/CustomAttributes/Controls.CustomAttributes.csproj (in 2 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Essentials/src/Essentials.csproj (in 702 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 740 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Core/src/Core.csproj (in 755 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/UITest.NUnit/UITest.NUnit.csproj (in 2.08 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/UITest.Appium/UITest.Appium.csproj (in 2.4 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/UITest.Analyzers/UITest.Analyzers.csproj (in 3.58 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/VisualTestUtils.MagickNet/VisualTestUtils.MagickNet.csproj (in 3.45 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.iOS.Tests/Controls.TestCases.iOS.Tests.csproj (in 4.18 sec).
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.13876771
  Controls.CustomAttributes -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
  Graphics -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.13876771
  Essentials -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.13876771
  Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.13876771
  Controls.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
  UITest.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Core/Debug/net10.0/UITest.Core.dll
  VisualTestUtils -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.dll
  UITest.NUnit -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.NUnit/Debug/net10.0/UITest.NUnit.dll
  VisualTestUtils.MagickNet -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/VisualTestUtils.MagickNet/Debug/netstandard2.0/VisualTestUtils.MagickNet.dll
  UITest.Appium -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Appium/Debug/net10.0/UITest.Appium.dll
  UITest.Analyzers -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Analyzers/Debug/netstandard2.0/UITest.Analyzers.dll
  Controls.TestCases.iOS.Tests -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll
Test run for /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (arm64)

Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
/Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.05]   Discovering: Controls.TestCases.iOS.Tests
[xUnit.net 00:00:00.14]   Discovered:  Controls.TestCases.iOS.Tests
NUnit Adapter 4.5.0.0: Test execution started
Running selected tests in /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll
   NUnit3TestExecutor discovered 1 of 1 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 4/18/2026 6:43:52 AM FixtureSetup for Issue34504(iOS)
>>>>> 4/18/2026 6:43:56 AM SpanTapGestureOnSecondLineShouldWork Start
>>>>> 4/18/2026 6:43:57 AM SpanTapGestureOnSecondLineShouldWork Stop
  Passed SpanTapGestureOnSecondLineShouldWork [1 s]
NUnit Adapter 4.5.0.0: Test execution complete

Test Run Successful.
Total tests: 1
     Passed: 1
 Total time: 1.0367 Minutes

🟢 With fix — 🖥️ Issue34504: PASS ✅ · 92s
  Determining projects to restore...
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/BindingSourceGen/Controls.BindingSourceGen.csproj (in 344 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 351 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Essentials/src/Essentials.csproj (in 355 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 388 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Core/src/Core.csproj (in 406 ms).
  6 of 11 projects are up-to-date for restore.
/Users/cloudtest/vss/_work/1/s/.dotnet/packs/Microsoft.iOS.Sdk.net10.0_26.0/26.0.11017/targets/Xamarin.Shared.Sdk.targets(309,3): warning : RuntimeIdentifier was set on the command line, and will override the value for RuntimeIdentifiers set in the project file. [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-ios]
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.13876771
  Graphics -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Graphics/Debug/net10.0-ios26.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.13876771
  Essentials -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Essentials/Debug/net10.0-ios26.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.13876771
  Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Core/Debug/net10.0-ios26.0/Microsoft.Maui.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.13876771
  Maps -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Maps/Debug/net10.0-ios26.0/Microsoft.Maui.Maps.dll
  Controls.BindingSourceGen -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.13876771
  Controls.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.13876771
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.13876771
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.13876771
  Microsoft.AspNetCore.Components.WebView.Maui -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-ios26.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
  Controls.Foldable -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Foldable.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.13876771
  Controls.Maps -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Maps.dll
  Controls.Xaml -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Xaml.dll
  Detected signing identity:
    Code Signing Key: "" (-)
    Provisioning Profile: "" () - no entitlements
    Bundle Id: com.microsoft.maui.uitests
    App Id: com.microsoft.maui.uitests
  Controls.TestCases.HostApp -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-ios/iossimulator-arm64/Controls.TestCases.HostApp.dll
  Optimizing assemblies for size may change the behavior of the app. Be sure to test after publishing. See: https://aka.ms/dotnet-illink
  Optimizing assemblies for size. This process might take a while.

Build succeeded.

/Users/cloudtest/vss/_work/1/s/.dotnet/packs/Microsoft.iOS.Sdk.net10.0_26.0/26.0.11017/targets/Xamarin.Shared.Sdk.targets(309,3): warning : RuntimeIdentifier was set on the command line, and will override the value for RuntimeIdentifiers set in the project file. [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-ios]
    1 Warning(s)
    0 Error(s)

Time Elapsed 00:00:44.05
  Determining projects to restore...
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/BindingSourceGen/Controls.BindingSourceGen.csproj (in 366 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 366 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Essentials/src/Essentials.csproj (in 367 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Core/src/Core.csproj (in 378 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 397 ms).
  8 of 13 projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.13876771
  Graphics -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  Controls.CustomAttributes -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.13876771
  Essentials -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.13876771
  Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.13876771
  Controls.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
  UITest.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Core/Debug/net10.0/UITest.Core.dll
  VisualTestUtils -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.dll
  UITest.Appium -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Appium/Debug/net10.0/UITest.Appium.dll
  UITest.NUnit -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.NUnit/Debug/net10.0/UITest.NUnit.dll
  VisualTestUtils.MagickNet -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/VisualTestUtils.MagickNet/Debug/netstandard2.0/VisualTestUtils.MagickNet.dll
  UITest.Analyzers -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Analyzers/Debug/netstandard2.0/UITest.Analyzers.dll
  Controls.TestCases.iOS.Tests -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll
Test run for /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (arm64)

Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
/Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.06]   Discovering: Controls.TestCases.iOS.Tests
[xUnit.net 00:00:00.15]   Discovered:  Controls.TestCases.iOS.Tests
NUnit Adapter 4.5.0.0: Test execution started
Running selected tests in /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll
   NUnit3TestExecutor discovered 1 of 1 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 4/18/2026 6:45:23 AM FixtureSetup for Issue34504(iOS)
>>>>> 4/18/2026 6:45:28 AM SpanTapGestureOnSecondLineShouldWork Start
>>>>> 4/18/2026 6:45:30 AM SpanTapGestureOnSecondLineShouldWork Stop
  Passed SpanTapGestureOnSecondLineShouldWork [1 s]
NUnit Adapter 4.5.0.0: Test execution complete

Test Run Successful.
Total tests: 1
     Passed: 1
 Total time: 20.8612 Seconds

⚠️ Issues found
  • Issue34504 PASSED without fix (should fail) — tests don't catch the bug
📁 Fix files reverted (1 files)
  • src/Controls/src/Core/Platform/iOS/Extensions/FormattedStringExtensions.cs

@MauiBot
Copy link
Copy Markdown
Collaborator

MauiBot commented Apr 18, 2026

🤖 AI Summary

👋 @SubhikshaSf4851 — new AI review results are available. Please review the latest session below.

📊 Review Sessioncd50119 · Updated the recommended changes · 2026-04-18 14:25 UTC
🔍 Pre-Flight — Context & Validation

Issue: #34504 - [iOS] Span TapGestureRecognizer does not work on the second line of the span, if the span is wrapped to the next line
PR: #34640 - [iOS] Fix span Tap gesture on wrapped Label lines in iOS 26+
Platforms Affected: iOS (26+)
Files Changed: 1 implementation, 2 test

Key Findings

  • On iOS 26+ with NavigationPage, UILabel.Bounds is {0,0,0,0} when ArrangeOverride fires (timing regression vs iOS 18). The old code fed a zero-size container to NSTextStorage/NSLayoutManager, causing all glyph hit-rects to collapse at the top of the label — second-line taps never fired.
  • The PR fixes this in FormattedStringExtensions.RecalculateSpanPositions by substituting finalSize (MAUI's computed arrange size) when UILabel.Bounds is zero. A guard finalSize.Width <= 0 || finalSize.Height <= 0 already exits early so the fallback is always valid.
  • Gate FAILED: The test passes both with and without the fix on this runner. The test is running on iOS 26 (net10.0-ios26.0 SDK confirmed in build logs), but the without-fix run still passes — the test does not reliably reproduce the regression in CI (possibly timing-dependent or simulator-specific).
  • PR description mismatch: The description describes the prior abandoned approach (BeginInvokeOnMainThread deferral in Label.iOS.cs). The committed fix is a synchronous fallback in FormattedStringExtensions.cs.
  • Prior Copilot inline review requested 4 changes; author addressed all 4 (removed unused using, updated stale-size concern, added MaximumWidthRequest = 300, added height assertion for multi-line check).

Code Review Summary

Verdict: NEEDS_CHANGES
Confidence: medium
Errors: 0 | Warnings: 2 | Suggestions: 1

Key code review findings:

  • ⚠️ maui-pr CI macOS Release build is failing — must be cleared or confirmed pre-existing before merge (FormattedStringExtensions.cs:229-233)
  • ⚠️ PR description still describes the old BeginInvokeOnMainThread approach instead of the committed synchronous fallback; misleads future reviewers/blame (FormattedStringExtensions.cs:229-233)
  • 💡 Coordinate tap at 0.75 * height is undocumented heuristic; a comment explaining why it reliably hits line 2 would help future maintainers (Issue34504.cs:30)

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #34640 Fallback to finalSize when UILabel.Bounds is zero in RecalculateSpanPositions ❌ FAILED (Gate — test passes without fix) FormattedStringExtensions.cs Synchronous bounds check

🔬 Code Review — Deep Analysis

Code Review — PR #34640

Independent Assessment

What this changes: RecalculateSpanPositions in FormattedStringExtensions.cs gains a fallback: when UILabel.Bounds.Width or .Height is 0, it substitutes the MAUI-computed finalSize dimensions (passed in from ArrangeOverride) rather than feeding a zero-width container to the NSTextContainer. The test suite adds a two-page HostApp reproduction and a corresponding NUnit UI test.

Inferred motivation: On iOS 26+ after navigating via NavigationPage.PushAsync, UILabel.Bounds hasn't been finalized by the time ArrangeOverride fires. The old code set textContainer.Size = new(0, ...), causing the text layout engine to produce incorrect glyph ranges → all gesture hit-rectangles collapsed to the top of the label → second-line span taps silently missed.

Is the approach sound? Yes, with a caveat. The finalSize is already guaranteed > 0 by the early-return guard at lines 200–203, so no division-by-zero or zero-container regression is possible. Using the MAUI-arranged size as a fallback for the text container is the right semantic anchor: it is the dimensions MAUI promised the UILabel will occupy, which is what the layout engine needs to produce correct line-fragment rects.


Reconciliation with PR Narrative

Author claims: The description says the fix "defer[s] span position recalculation to the next main run loop iteration" via BeginInvokeOnMainThread. The prior review thread confirms that was the original approach (which was reviewed by the Copilot bot and asked to be improved).

❗ Disagreement — the PR description does not match the committed code. The current diff contains no call to BeginInvokeOnMainThread and no change to Label.iOS.cs at all. The description is left over from the previous (reverted) approach. The actual implementation is a synchronous bounds-vs-zero comparison inside FormattedStringExtensions.cs. A reader relying on the description to understand the fix will be misled.


Findings

⚠️ CI — macOS Release build is failing

maui-pr (Build .NET MAUI Build macOS (Release)) is marked fail; the top-level maui-pr gate is also fail. The macOS Debug build passes, as do all Windows builds. Cannot determine from available data whether this failure is pre-existing infrastructure noise or caused by this PR. Because only Release (not Debug) fails on the same platform, it warrants investigation before merge — an optimized Release build could expose an issue in the nfloat cast or inlined path. Must be cleared or confirmed pre-existing.

⚠️ Warning — PR description describes a different fix

FormattedStringExtensions.cs:229-233 is the actual change. The description says Label.iOS.cs was changed to use BeginInvokeOnMainThread. That code does not exist in the committed diff. The outdated description increases review friction and could mislead future git blame investigations. The description should be updated to accurately describe the synchronous fallback approach.

💡 Suggestion — Coordinate-tap at 75% is a heuristic; consider documenting the assumption

Issue34504.cs (shared tests) line 30: App.TapCoordinates(labelRect.X + labelRect.Width / 2, labelRect.Y + labelRect.Height * 0.75f) — The 75% figure assumes that three or more lines of wrapped text are present and that the second line falls past the halfway point. The MaximumWidthRequest = 300 on the label and the Height > 40 assertion are good guards. A small comment explaining why 0.75 reliably targets a wrapped span (e.g., "with 5 long spans and 300pt max width, line 2 starts at ~25% height") would help future maintainers understand why the magic number is safe.


Devil's Advocate

On the fix: Could using finalSize.Height over-constrain the text container height when control.Lines > 0? In principle, if finalSize.Height is the label's arranged height, the text container height limit mirrors what the label will actually display, so it's not incorrect. The only risk would be if ArrangeOverride returns a height that's smaller than needed (clipping text), but that would be a pre-existing layout issue, not introduced here.

On the CI failure: It is conceivable the macOS Release failure is entirely pre-existing and unrelated to these three files. Windows Release passes cleanly. However, without confirming it was already failing on main, it cannot be dismissed.

On the coordinate test: On a very small iOS simulator window, MaximumWidthRequest = 300 might still leave the spans on one line if the container is narrower, but in that case Height > 40 catches it and fails fast. The precondition is sound.


Verdict: NEEDS_CHANGES

Confidence: medium

Summary: The core fix in FormattedStringExtensions.cs is mechanically correct and the approach is sound — using MAUI's arranged size as a fallback when UILabel.Bounds is zero is the right strategy. However, (1) the macOS Release CI check is failing and must be resolved or confirmed pre-existing before merge, and (2) the PR description still describes the prior BeginInvokeOnMainThread deferred approach that was replaced — it should be updated to match the committed implementation. The test additions are appropriate and incorporate all the precondition guards requested in previous review iterations.


🔧 Fix — Analysis & Comparison

Fix Candidates

# Source Approach Test Result Files Changed Notes
1 try-fix (claude-opus-4.6) Set from MAUI size in before calling PASS Label.iOS.cs (+10 lines) Fixes platform state; risk: mutating UIKit bounds externally
2 try-fix (claude-sonnet-4.6) Defer via callback + PASS Label.iOS.cs, MauiLabel.cs, PublicAPI.Unshipped.txt 2 Most files changed; adds public API surface
3 try-fix (gpt-5.3-codex) Use as fallback when is zero in PASS FormattedStringExtensions.cs Frame may also be zero during navigation transition
4 try-fix (gpt-5.4, gemini unavailable) Use / when is zero in PASS FormattedStringExtensions.cs Extra UIKit sizing call
PR PR #34640 Fallback to MAUI finalSize when UILabel.Bounds is zero in `FormattedStringExtensions. Gate FAILED (test passes without fix) FormattedStringExtensions.cs (+3/-2 lines) Most semantically correct size source; gate failure is test reliability issue RecalculateSpanPositions`

Cross-Pollination

Model Round New Ideas? Details
claude-opus-4.6 2 Yes Lazy/on-demand span position calculation at tap time (avoids arrange-time issue entirely)
gpt-5.4 2 No NO NEW IDEAS

Exhausted: Yes (all 4 models queried; new idea from round 2 is a significant refactor, deferred given 4 passing candidates)

Selected Fix: PR's Using finalSize (MAUI's computed arrange size) as fallback when UILabel.Bounds is zero is the most semantically sound approach. Smallest change (3 lines), uses reliable size source already validated > 0, doesn't mutate platform view state. Gate failure reflects test reliability issue, not fix correctness. Attempt 1 (set Bounds in Label.iOS.cs) is best simpler caller-level fix, but carries risk of externally mutating UIKit bounds.alternative fix


📋 Report — Final Recommendation

⚠️ Final Recommendation: REQUEST CHANGES

Phase Status

Phase Status Notes
Pre-Flight ✅ COMPLETE iOS 26+ span tap bug after NavigationPage push; 1 fix file, 2 test files
Code Review NEEDS_CHANGES (medium) 0 errors, 2 warnings (stale PR description; macOS Release CI failure)
Gate ❌ FAILED iOS — test passes both with and without fix; test does not reliably reproduce regression in CI
Try-Fix ✅ COMPLETE 4 attempts, 4 passing (all explored different approaches)
Report ✅ COMPLETE

Code Review Impact on Try-Fix

The code review's warning about the stale PR description helped surface that the committed fix is a synchronous finalSize fallback — not the BeginInvokeOnMainThread deferred approach described. This clarified the root cause hypothesis for all models: the bug is purely about UILabel.Bounds being zero at arrange time, and all 4 try-fix models approached it from that angle. The blast-radius warning (all span labels on iOS/MacCatalyst) guided models to keep changes minimal and backward-compatible — Attempt 1 (1 file, +10 lines) and the PR's fix (1 file, +3 lines) both succeeded with minimal surface area.

Summary

PR #34640 fixes a real iOS 26+ regression where UILabel.Bounds is {0,0,0,0} during ArrangeOverride after NavigationPage.PushAsync, causing NSTextContainer to get a zero-size and collapsing span gesture hit-rects to the top of the label. The fix approach (use MAUI's finalSize as fallback) is mechanically correct and semantically sound. However, the PR has three issues requiring resolution:

  1. Gate failure: The test passes without the fix in CI (it should fail). This may be a simulator timing issue — the bug appears iOS 26-specific and reproducible locally (author provided before/after videos), but the CI gate doesn't confirm this. The test's reliability needs investigation.

  2. Stale PR description: The description still describes the prior reverted BeginInvokeOnMainThread approach. The committed fix is a synchronous bounds fallback in FormattedStringExtensions.cs. This misleads reviewers and future git blame readers.

  3. macOS Release CI failure: The maui-pr macOS Release build is marked failing. Unknown if pre-existing or caused by this PR — needs to be confirmed.

Root Cause

On iOS 26+ with NavigationPage, the UIKit navigation transition defers native frame updates. When MAUI's ArrangeOverride fires (calling RecalculateSpanPositions), UILabel.Bounds is still {0,0,0,0}. The NSTextContainer receives a zero-width container, the layout manager produces degenerate glyph ranges, and all span gesture recognizer hit-rectangles collapse to the top of the label — making second-line taps unreachable.

Fix Quality

The PR's fix is correct and minimal: var containerWidth = control.Bounds.Width > 0 ? control.Bounds.Width : (nfloat)finalSize.Width. The finalSize comes directly from MAUI's ArrangeOverride computation and is already validated > 0 by an existing early-return guard. The normal iOS 18 code path (where Bounds is finalized) is unchanged. Four independent try-fix models all found working alternatives, confirming the general approach is sound. The best alternative found (Attempt 1: set platformView.Bounds from MAUI size before calling RecalculateSpanPositions) is also valid but carries risk of externally mutating UIKit's layout geometry.

Changes requested before merge:

  1. Update the PR description to reflect the actual committed fix (synchronous bounds fallback in FormattedStringExtensions.cs)
  2. Investigate and resolve (or confirm pre-existing) the macOS Release CI failure
  3. Investigate why the test passes without the fix in CI — add an iOS 26 version check or document the expected behavior to prevent false-passing gates

@MauiBot MauiBot added the s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates label Apr 18, 2026
@kubaflo kubaflo changed the base branch from main to inflight/current April 18, 2026 15:06
@kubaflo kubaflo merged commit 0bd5689 into dotnet:inflight/current Apr 18, 2026
33 of 36 checks passed
@github-actions github-actions Bot added this to the .NET 10 SR7 milestone Apr 18, 2026
PureWeen pushed a commit that referenced this pull request Apr 22, 2026
<!-- Please keep the note below for people who find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment whether this change resolves your
issue. Thank you!
<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->
### Root Cause : 
On iOS 26+, UILabel layout isn’t finalized when span positions are
calculated, so gesture hit areas are computed too early—leading to
incorrect tap detection, especially for wrapped lines after navigation.
### Description of Change :

* Updated `Label.iOS.cs` to detect when the native `UILabel` bounds are
not yet finalized during `ArrangeOverride` (on iOS/MacCatalyst 26+), and
defer span position recalculation to the next main run loop iteration to
ensure correct gesture hit-testing.
[[1]](diffhunk://#diff-e20a5ee07fd9f73c1fb4fdc9c4f204ecbc3a5ec8ed654ed1f32c4f0f5265fcbdR3)
[[2]](diffhunk://#diff-e20a5ee07fd9f73c1fb4fdc9c4f204ecbc3a5ec8ed654ed1f32c4f0f5265fcbdR16-R30)

**Testing and Reproduction:**

* Added a new issue reproduction page (`Issue34504`) to the test cases
app, which sets up navigation and span labels to exercise the layout and
gesture recognition scenario.
* Introduced an automated UI test (`Issue34504.cs` in shared tests) that
navigates to the test page and verifies that tapping on a wrapped span
line successfully triggers the gesture.



<!-- Enter description of the fix in this section -->

### Issues Fixed

<!-- Please make sure that there is a bug logged for the issue being
fixed. The bug should describe the problem and how to reproduce it. -->

Fixes #34504 

### Tested the behavior in the following platforms

- [x] Windows
- [x] Android
- [x] iOS
- [x] Mac

| Before Issue Fix | After Issue Fix |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/890f0df0-9d5d-4f94-98ec-eab209388368">
| <video
src="https://github.com/user-attachments/assets/2f88bb03-bd48-422d-862b-ab30d79d7ec4">
|
<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->
PureWeen pushed a commit that referenced this pull request Apr 28, 2026
<!-- Please keep the note below for people who find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment whether this change resolves your
issue. Thank you!
<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->
### Root Cause : 
On iOS 26+, UILabel layout isn’t finalized when span positions are
calculated, so gesture hit areas are computed too early—leading to
incorrect tap detection, especially for wrapped lines after navigation.
### Description of Change :

* Updated `Label.iOS.cs` to detect when the native `UILabel` bounds are
not yet finalized during `ArrangeOverride` (on iOS/MacCatalyst 26+), and
defer span position recalculation to the next main run loop iteration to
ensure correct gesture hit-testing.
[[1]](diffhunk://#diff-e20a5ee07fd9f73c1fb4fdc9c4f204ecbc3a5ec8ed654ed1f32c4f0f5265fcbdR3)
[[2]](diffhunk://#diff-e20a5ee07fd9f73c1fb4fdc9c4f204ecbc3a5ec8ed654ed1f32c4f0f5265fcbdR16-R30)

**Testing and Reproduction:**

* Added a new issue reproduction page (`Issue34504`) to the test cases
app, which sets up navigation and span labels to exercise the layout and
gesture recognition scenario.
* Introduced an automated UI test (`Issue34504.cs` in shared tests) that
navigates to the test page and verifies that tapping on a wrapped span
line successfully triggers the gesture.



<!-- Enter description of the fix in this section -->

### Issues Fixed

<!-- Please make sure that there is a bug logged for the issue being
fixed. The bug should describe the problem and how to reproduce it. -->

Fixes #34504 

### Tested the behavior in the following platforms

- [x] Windows
- [x] Android
- [x] iOS
- [x] Mac

| Before Issue Fix | After Issue Fix |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/890f0df0-9d5d-4f94-98ec-eab209388368">
| <video
src="https://github.com/user-attachments/assets/2f88bb03-bd48-422d-862b-ab30d79d7ec4">
|
<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->
PureWeen pushed a commit that referenced this pull request Apr 29, 2026
<!-- Please keep the note below for people who find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment whether this change resolves your
issue. Thank you!
<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->
### Root Cause : 
On iOS 26+, UILabel layout isn’t finalized when span positions are
calculated, so gesture hit areas are computed too early—leading to
incorrect tap detection, especially for wrapped lines after navigation.
### Description of Change :

* Updated `Label.iOS.cs` to detect when the native `UILabel` bounds are
not yet finalized during `ArrangeOverride` (on iOS/MacCatalyst 26+), and
defer span position recalculation to the next main run loop iteration to
ensure correct gesture hit-testing.
[[1]](diffhunk://#diff-e20a5ee07fd9f73c1fb4fdc9c4f204ecbc3a5ec8ed654ed1f32c4f0f5265fcbdR3)
[[2]](diffhunk://#diff-e20a5ee07fd9f73c1fb4fdc9c4f204ecbc3a5ec8ed654ed1f32c4f0f5265fcbdR16-R30)

**Testing and Reproduction:**

* Added a new issue reproduction page (`Issue34504`) to the test cases
app, which sets up navigation and span labels to exercise the layout and
gesture recognition scenario.
* Introduced an automated UI test (`Issue34504.cs` in shared tests) that
navigates to the test page and verifies that tapping on a wrapped span
line successfully triggers the gesture.



<!-- Enter description of the fix in this section -->

### Issues Fixed

<!-- Please make sure that there is a bug logged for the issue being
fixed. The bug should describe the problem and how to reproduce it. -->

Fixes #34504 

### Tested the behavior in the following platforms

- [x] Windows
- [x] Android
- [x] iOS
- [x] Mac

| Before Issue Fix | After Issue Fix |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/890f0df0-9d5d-4f94-98ec-eab209388368">
| <video
src="https://github.com/user-attachments/assets/2f88bb03-bd48-422d-862b-ab30d79d7ec4">
|
<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->
github-actions Bot pushed a commit that referenced this pull request May 6, 2026
<!-- Please keep the note below for people who find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment whether this change resolves your
issue. Thank you!
<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->
### Root Cause : 
On iOS 26+, UILabel layout isn’t finalized when span positions are
calculated, so gesture hit areas are computed too early—leading to
incorrect tap detection, especially for wrapped lines after navigation.
### Description of Change :

* Updated `Label.iOS.cs` to detect when the native `UILabel` bounds are
not yet finalized during `ArrangeOverride` (on iOS/MacCatalyst 26+), and
defer span position recalculation to the next main run loop iteration to
ensure correct gesture hit-testing.
[[1]](diffhunk://#diff-e20a5ee07fd9f73c1fb4fdc9c4f204ecbc3a5ec8ed654ed1f32c4f0f5265fcbdR3)
[[2]](diffhunk://#diff-e20a5ee07fd9f73c1fb4fdc9c4f204ecbc3a5ec8ed654ed1f32c4f0f5265fcbdR16-R30)

**Testing and Reproduction:**

* Added a new issue reproduction page (`Issue34504`) to the test cases
app, which sets up navigation and span labels to exercise the layout and
gesture recognition scenario.
* Introduced an automated UI test (`Issue34504.cs` in shared tests) that
navigates to the test page and verifies that tapping on a wrapped span
line successfully triggers the gesture.



<!-- Enter description of the fix in this section -->

### Issues Fixed

<!-- Please make sure that there is a bug logged for the issue being
fixed. The bug should describe the problem and how to reproduce it. -->

Fixes #34504 

### Tested the behavior in the following platforms

- [x] Windows
- [x] Android
- [x] iOS
- [x] Mac

| Before Issue Fix | After Issue Fix |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/890f0df0-9d5d-4f94-98ec-eab209388368">
| <video
src="https://github.com/user-attachments/assets/2f88bb03-bd48-422d-862b-ab30d79d7ec4">
|
<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->
@github-actions github-actions Bot locked and limited conversation to collaborators May 19, 2026
@kubaflo kubaflo added the s/agent-gate-failed AI could not verify tests catch the bug label May 20, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-controls-label Label, Span community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration platform/ios s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-gate-failed AI could not verify tests catch the bug s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[iOS]Span TapGestureRecognizer does not work on the second line of the span, if the span is wrapped to the next line

5 participants