Skip to content

June 8th, Candidate#35716

Open
PureWeen wants to merge 163 commits into
mainfrom
inflight/candidate
Open

June 8th, Candidate#35716
PureWeen wants to merge 163 commits into
mainfrom
inflight/candidate

Conversation

@PureWeen

@PureWeen PureWeen commented Jun 2, 2026

Copy link
Copy Markdown
Member

No description provided.

KarthikRajaKalaimani and others added 30 commits June 2, 2026 14:33
)

<!-- Please let the below note in for people that 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 if this change resolves your issue.
Thank you!

### Issue Details:

Horizontalspacing / Verticalspacing is not not applied to the first
column in GridItemLayout using CollectionView on Android platform.
        
### Root Cause:

The grid spacing was not being distributed symmetrically across the
active layout implementations, so edge items did not fully participate
when spacing changed at runtime.

### Description of Change:

- On Android, the fix in MauiRecyclerView.cs changes how RecyclerView
padding is handled for GridItemsLayout. Android was already using
SpacingItemDecoration, which applies half-spacing on all four sides of
each item. Previously, negative RecyclerView padding canceled that
spacing at the control edges. The branch keeps that negative-padding
behavior for non-grid layouts, but disables it for GridItemsLayout,
allowing the grid’s half-spacing to remain visible at the outer
perimeter. This makes the first row and first column visually respond
when spacing changes, but it also changes the grid behavior from spacing
only between items to spacing around the outside edges as well.

**Tested the behavior in the following platforms:**

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

### Reference:

N/A

### Issues Fixed:

Fixes  #34257      

### Screenshots
| Before  | After  |
|---------|--------|
| <Video
src="https://github.com/user-attachments/assets/578dda69-1d60-474c-a6d8-23b3f9d29a50"
Width="300" Height="600"> | <Video
src="https://github.com/user-attachments/assets/7f3826e6-5922-4b6f-a6b9-de581b7db6c3"
Width="300" Height="600"> |
<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Description of Change

<!-- Enter description of the fix in this section -->
This pull request standardizes the namespace declarations for several
test case files related to issues in the test suite. The changes ensure
that all files use the correct `Microsoft.Maui.TestCases.Tests.Issues`
namespace, improving consistency and maintainability.

**Namespace corrections:**

* Changed the namespace in `Issue22075.cs` from
`Microsoft.Maui.TestCases.Tests.Issue` to
`Microsoft.Maui.TestCases.Tests.Issues` to match the naming convention.
* Updated the namespace in `Issue28968.cs` from
`Microsoft.Maui.TestCases.Tests.Tests.Issues` to
`Microsoft.Maui.TestCases.Tests.Issues`.
* Updated the namespace in `Issue29588.cs` from
`Microsoft.Maui.TestCases.Tests.Tests.Issues` to
`Microsoft.Maui.TestCases.Tests.Issues`.
* Changed the namespace in `Issue33227.cs` from
`Maui.Controls.TestCases.Tests.Issues` to
`Microsoft.Maui.TestCases.Tests.Issues`.
…35092)

<!-- 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. !!!!!!!
-->

This pull request addresses an issue where the `WebView` rendered blank
when both a `HybridWebView` and a regular `WebView` coexisted in the
same Windows (UWP) app. The main fix ensures that `HybridWebView` only
creates a custom `CoreWebView2Environment` if custom settings are
provided, allowing both controls to share the default environment and
preventing conflicts. Additionally, new test cases have been added to
verify the fix.
### Description of Change
**Bug fix for WebView and HybridWebView coexistence:**

* Updated `HybridWebViewHandler.Windows.cs` so that a custom
`CoreWebView2Environment` is created only if the user provides custom
settings; otherwise, the default shared environment is used. This
prevents conflicts when both `HybridWebView` and `WebView` are present
in the same app, resolving the blank rendering issue.
[[1]](diffhunk://#diff-9adaedb7571e93283664d8e3db8d34930d748bbe1207eb004f53e25e08eaaaeaR310-R325)
[[2]](diffhunk://#diff-9adaedb7571e93283664d8e3db8d34930d748bbe1207eb004f53e25e08eaaaeaR337-R341)

**Test coverage improvements:**

* Added a new UI test in
`TestCases.Shared.Tests/Tests/Issues/Issue34558.cs` to verify that the
regular `WebView` renders content successfully when coexisting with a
`HybridWebView`.
* Introduced a new test case page in
`TestCases.HostApp/Issues/Issue34558.cs` that sets up both controls and
provides UI elements for automated verification.



<!-- 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 #34558 
### Tested the behavior in the following platforms

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

| Before Issue Fix | After Issue Fix |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/4ba3435a-99af-4e7e-82be-6dbb588e07b6">
| <video
src="https://github.com/user-attachments/assets/fb5b1e22-b317-4421-829c-0f9b15c84e77">
|
<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->
…PI changes) (#35095)

<!-- Please let the below note in for people that 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 if this change resolves your issue.
Thank you!

### Description of Change

Enables third-party platform backends (for example Maui.Gtk) to provide
their own `DisplayAlertAsync` / `DisplayActionSheetAsync` /
`DisplayPromptAsync` implementations without MAUI exposing any new
public API. This complements #33267: because that PR introduces a new
public interface, it must wait for .NET 11. This PR solves the same
problem using already-shipped public argument types, so it is shippable
in .NET 10.

`AlertManager.Subscribe()` now keeps the existing explicit internal
`IAlertManagerSubscription` path, then checks for keyed delegate
registrations before falling back to the platform default. The delegate
signatures use only existing public types:

```csharp
Func<Page, AlertArguments,       Task<bool>>
Func<Page, ActionSheetArguments, Task<string>>
Func<Page, PromptArguments,      Task<string>>
```

The registrations are keyed so MAUI does not accidentally consume
unrelated `Func<>` services:

| Dialog | Service key |
|---|---|
| Alert | `Microsoft.Maui.Controls.DisplayAlert` |
| Action sheet | `Microsoft.Maui.Controls.DisplayActionSheet` |
| Prompt | `Microsoft.Maui.Controls.DisplayPrompt` |

Consumer usage:

```csharp
builder.Services.AddKeyedSingleton<Func<Page, AlertArguments, Task<bool>>>(
    "Microsoft.Maui.Controls.DisplayAlert",
    async (page, args) =>
    {
        return await MyGtkDialog.ShowAsync(args.Title, args.Message, args.Accept, args.Cancel);
    });
```

If any keyed delegate is registered, MAUI wraps it in a new internal
`DelegateAlertSubscription`. Registered operations dispatch to their
delegate; unregistered operations fall through to the platform default.
The delegate returns the dialog result and MAUI completes the
corresponding `AlertArguments`, `ActionSheetArguments`, or
`PromptArguments` internally. If the delegate returns `null`, faults, or
cancels, the caller observes that through the original `Display*Async`
task instead of hanging silently.

Precedence order in `Subscribe()`:

1. Explicit `IAlertManagerSubscription` service (existing internal path,
unchanged)
2. Keyed result-returning delegate convention (new)
3. Platform default subscription (existing fallback)

### Notes for reviewers

- Zero public API surface: no `PublicAPI.*.txt` changes. The new
`DelegateAlertSubscription` class and key constants are internal;
consumers use literal string keys documented on the existing argument
types.
- Keyed registrations are intentional. Unkeyed `Func<>` services are
ignored to avoid accidental collisions.
- The delegate returns the dialog result instead of calling
`args.SetResult(...)`. This matches the built-in async platform pattern
where MAUI completes the argument after awaiting the native dialog
result.
- Per-operation fall-through is intentional. A backend can override just
alerts and keep the platform action sheet/prompt, for example.
- `OnPageBusy` is excluded from the convention (obsolete in .NET 10,
removed in .NET 11) and always routes to the fallback.
- When .NET 11 ships a proper public
`IAlertManager`/`IAlertDialogProvider`, this delegate convention can
stay as a lightweight alias or be deprecated. Either way, .NET 10
consumers are unblocked now.

### Tests

Unit coverage in `AlertManagerTests.cs` includes:

- Alert, action sheet, and prompt delegate dispatch
- Returned delegate results completing the original `Display*Async`
caller
- Unregistered operation fall-through
- Unkeyed delegate services being ignored
- Explicit `IAlertManagerSubscription` precedence
- Synchronous and asynchronous delegate faults
- Delegate cancellation forwarding
- Null task contract violation

Focused `AlertManagerTests` pass locally: 21/21.

### Issues Fixed

Fixes #34104

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
…ing ToPlatform and subsequent property changes (#31159)

<!-- Please let the below note in for people that 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 if this change resolves your issue.
Thank you!

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Description of Change

- The iOS Label performance was improved in PR #30864. In that PR, the
Label and Entry Feature Matrix test sample and script were modified,
which caused discrepancies in the expected images due to changes which
is due to test sample's default property values. In this PR, I updated
the test sample and re-saved the images accordingly.

- Windows - The Entry is now unfocused, so I re-saved the latest image.
- Android - I modified the test sample by altering the default values
and re-saved two images.

Additionally, while working on the test sample changes, I identified and
fixed issues in FormattedStringExtensions.

These updates improve formatted text rendering on iOS by correctly
propagating span properties (font, character spacing, and line-break
settings) from the label to each span. The layout logic is also more
robust, falling back to MAUI’s calculated size when iOS has not yet
provided a valid label size, preventing incorrect text positioning and
rendering issues.

### 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. -->

Contributing to #30864

---------

Co-authored-by: KarthikRajaKalaimani <92777139+KarthikRajaKalaimani@users.noreply.github.com>
Co-authored-by: Jakub Florkowski <kubaflo123@gmail.com>
Co-authored-by: albyrock87 <albyrock87@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
# Conflicts:
#	src/Controls/tests/TestCases.HostApp/Issues/Issue34671.cs
The Visual Studio signing scan flags unsigned files inside MAUI workload
pack MSIs. This PR adds signing configuration for two categories of
unsigned files:

### 1. Unsigned `.cab` files (75 files across 75 payloads)

Every MAUI workload pack MSI contains an embedded `cab1.cab.cab` cabinet
archive that is currently unsigned. This affects 69 `maui*` payloads and
6 `aspnetcorewebviewmaui*` payloads across net9.0/net10.0 ×
arm64/x64/x86.

**Fix:** Add `FileExtensionSignInfo` for `.cab` with `Microsoft400`
(which Arcade auto-converts to `MicrosoftDotNet500` since
`UseDotNetCertificate` is `true`).

**Affected payloads (cab):**
- `mauicontrols{10020100200,90120901200}{arm64,x64,x86}`
- `mauicontrolsbuildtasks{10020100200,90120901200}{arm64,x64,x86}`
- `mauicontrolscompatibility90120901200{arm64,x64,x86}`
- `mauicontrolscore{10020100200,90120901200}{arm64,x64,x86}`
- `mauicontrolsxaml{10020100200,90120901200}{arm64,x64,x86}`
- `mauicore{10020100200,90120901200}{arm64,x64,x86}`
- `mauiessentials{10020100200,90120901200}{arm64,x64,x86}`
- `mauigraphics{10020100200,90120901200}{arm64,x64,x86}`
- `mauigraphicswindows{10020100200,90120901200}{arm64,x64,x86}`
- `mauiresizetizer{10020100200,90120901200}{arm64,x64,x86}`
- `mauisdknet{10,9}{10020100200,90120901200}{arm64,x64,x86}`
- `mauitemplatesnet{10,9}{10020100200,90120901200}{arm64,x64,x86}`
- `aspnetcorewebviewmaui{10020100200,90120901200}{arm64,x64,x86}`

### 2. Unsigned `ReconnectModal.razor.js` (3 files)

The Blazor reconnect modal script from
`Microsoft.AspNetCore.Components.Web` is packed into
`mauitemplatesnet10` workload MSIs without a signature.

**Fix:** Add `FileSignInfo` for `ReconnectModal.razor.js` with
`Microsoft400`.

**Affected payloads (js):**
- `mauitemplatesnet1010020100200{arm64,x64,x86}`
…latform (#35179)

<!-- Please let the below note in for people that 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 if this change resolves your issue.
Thank you!

### Issue Details:

DragGestureRecognizer.DropCompleted event not firing in Android platform
       
### Root Cause:

DragAndDropGestureHandler.SetupHandlerForDrop() only called
SetOnDragListener(this) when the view had a DropGestureRecognizer. On
Android, DragAction.Ended is only delivered to views that have a drag
listener registered. A view with only a DragGestureRecognizer (no
DropGestureRecognizer) never registered a listener → never received
DragAction.Ended → HandleDropCompleted never called → DropCompleted
event never fired.

### Description of Change:

The fix is in
src/Controls/src/Core/Platform/Android/DragAndDropGestureHandler.cs.
Modified the listener registration for drag-source-only views (those
with no DropGestureRecognizer) is now done just before
StartDragAndDrop() is called, scoping it to the active drag and
preventing sibling views in the same layout from accidentally becoming
drag listeners. In the DragAction.Ended handler, the fix always
dispatches DropCompleted to the tracked dragSourceElement regardless of
which view received the event — since on Android, DragAction.Ended can
arrive on a non-source view first. A one-shot DropCompletedSent flag on
the local drag state prevents the event from firing more than once. Once
the source view receives DragAction.Ended, the temporary listener is
unregistered to restore the original state.

**Tested the behavior in the following platforms: **

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

### Reference:

N/A

### Issues Fixed:

Fixes  #17554          

### Screenshots
| Before  | After  |
|---------|--------|
| <Video width="300" height="600"
src="https://github.com/user-attachments/assets/243dec05-a560-4d26-87dd-cb6e8b99ab27"
/> | <Video width="300" height="600"
src="https://github.com/user-attachments/assets/3137deb3-4f45-476e-8e96-15661609c546"
/> |
- ICrossPlatformLayout.CrossPlatformArrange can call LayoutButton with a
null button so it should be prepared for that.

Fixes #31048

---------
…35086)

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

<!-- Please let the below note in for people that 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 if this change resolves your issue.
Thank you!


<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Issue Details
TabbedPage tab titles get truncated on Android when there are more than
3 tabs (e.g., "New Tab 1" shows as "N..."). Tabs should scroll
horizontally and show full titles.

### Root Cause
TabbedPageManager.cs creates the Android TabLayout with TabMode =
TabLayout.ModeFixed, which divides screen width equally among all tabs.

### Description of Change
Changed TabMode from ModeFixed to ModeScrollable in which sizes tabs to
fit their content and enables horizontal scrolling.
 

Validated the behavior in the following platforms
 
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac
 
### Issues Fixed
  
Fixes #16470 

### Output  ScreenShot

|Before|After|
|--|--|
| <video
src="https://github.com/user-attachments/assets/1e984577-08aa-4091-b1fc-53bac5511154"
>| <video
src="https://github.com/user-attachments/assets/8c3ef77b-5d1a-480c-8e33-c3f485d04b53">|
…ebViewHandler in AddControlsHandlers (#34868)

`AOTTemplateTest.PublishNativeAOT` and
`PublishNativeAOTRootAllMauiAssemblies` fail on Android NativeAOT
because the Android ILC (SDK 36.99.0-preview.3.10) emits unexpected
`IL3050` warnings for `HybridWebViewHandler` constructors—despite the
call site already being correctly guarded by a
`[FeatureGuard]`-annotated feature switch.

## Why the warnings appear

`HybridWebViewHandler` carries
`[RequiresDynamicCode]`/`[RequiresUnreferencedCode]` because it uses
dynamic `System.Text.Json` serialization. The registration in
`AddControlsHandlers` is inside a proper feature guard:

```csharp
// RuntimeFeature.IsHybridWebViewSupported has:
//   [FeatureGuard(typeof(RequiresDynamicCodeAttribute))]
//   [FeatureGuard(typeof(RequiresUnreferencedCodeAttribute))]
// MauiHybridWebViewSupported=false is set by MSBuild targets when PublishAot=true
if (RuntimeFeature.IsHybridWebViewSupported)
{
    handlersCollection.AddHandler<HybridWebView, HybridWebViewHandler>();
}
```

The iOS/macCatalyst NativeAOT ILC correctly honors `[FeatureGuard]` and
suppresses the warnings. The Android NativeAOT ILC does not, so
`IL3050`/`IL2026` leak through and break the test's strict
warning-baseline check.

## Fix

Explicitly suppress with `#pragma` at the affected call site—the same
pattern used elsewhere in the codebase (`ResourceDictionaryHelpers.cs`,
etc.) for ILC warnings on code that is provably safe via a feature
guard:

```csharp
if (RuntimeFeature.IsHybridWebViewSupported)
{
    // NOTE: not registered under NativeAOT or TrimMode=Full scenarios.
    // IL2026/IL3050 suppressed because IsHybridWebViewSupported has [FeatureGuard] annotations
    // for both RequiresUnreferencedCode and RequiresDynamicCode. The Android NativeAOT ILC does
    // not honor [FeatureGuard] for warning suppression (unlike iOS/macCatalyst), so suppress explicitly.
#pragma warning disable IL2026, IL3050
    handlersCollection.AddHandler<HybridWebView, HybridWebViewHandler>();
#pragma warning restore IL2026, IL3050
}
```

No baseline changes needed—the pragma suppression is respected by the
ILC so the warnings are no longer emitted.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: mattleibow <1096616+mattleibow@users.noreply.github.com>
…ide the Border (#30408)

<!-- Please let the below note in for people that 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 if this change resolves your issue.
Thank you!

### Root Cause of the issue



- On Windows, when a ContentView with a clip applied during the
SizeChanged event is placed inside a Border, both the ContentView
(through WrapperView) and the Border's content (via ContentPanel)
attempt to apply their own clips to the same visual element.

- The clip set in the ContentPanel.UpdateClip method of the Border is
applied after the WrapperView has already set its clip, resulting in the
Border overwriting the clip geometry originally applied.



### Description of Change



- The fix introduces a condition in ContentPanel.UpdateClip that checks:
- Whether the content's visual already has a clip (visual.Clip is not
null)
- Whether the content is wrapped by a WrapperView (Content.Parent is
WrapperView)
- If both conditions are met, the ContentPanel skips applying its own
clip to the content, allowing the ContentView’s clip (set by the
WrapperView) to be preserved.



### Issues Fixed



Fixes #30404 



### Tested the behaviour in the following platforms



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



### Screenshot



| Before Issue Fix | After Issue Fix |
|----------|----------|
| <img
src="https://github.com/user-attachments/assets/04381895-5d99-4ac8-9a2e-7d35aaa03dd4">
| <img
src="https://github.com/user-attachments/assets/04938f65-5c0a-4a4b-9676-c34c3ac30378">
|
…nt Width (#35213)

<!-- Please let the below note in for people that 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 if this change resolves your issue.
Thank you!

### Issue Details:

CollectionView's Header / Footer is not expanded to its content width in
iOS and Mac platform
       
### Root Cause:

In the iOS/MacCatalyst CollectionView2 implementation,
StructuredItemsViewController2 and GroupableItemsViewController2 both
have a GetViewForSupplementaryElement() method responsible for creating
header and footer views. When a TemplatedCell2 is dequeued as a
supplementary view, its ScrollDirection property was never set — it
silently defaulted to UICollectionViewScrollDirection.Vertical. This was
an oversight, because regular item cells in GetCell() already correctly
assigned ScrollDirection. The missing assignment fed through to
GetMeasureConstraints() in TemplatedCell2, which uses ScrollDirection to
decide how to constrain the cell during measurement: for a horizontal
grid, a Vertical direction incorrectly constrains the cell's width to
the estimated value (~30pt from LayoutFactory2) instead of leaving it
unconstrained, causing header/footer labels to be clipped to a tiny
width and become inaccessible in the UI tree.

### Description of Change:

The fix is a one-line addition in each of the two affected view
controllers, mirroring the pattern already used in GetCell(). In
StructuredItemsViewController2.GetViewForSupplementaryElement(),
templatedCell.ScrollDirection = ScrollDirection is set before calling
UpdateTemplatedSupplementaryView. The same line is added in
GroupableItemsViewController2.GetViewForSupplementaryElement() for group
header/footer cells. With ScrollDirection correctly propagated,
GetMeasureConstraints() leaves the width unconstrained for horizontal
grids, allowing headers and footers to self-size to their full content
width. Vertical layouts are unaffected since they already defaulted to
Vertical, and the change has no impact on Android or Windows as Items2
is iOS/MacCatalyst-only.

**Tested the behavior in the following platforms: **

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

### Reference:

N/A

### Issues Fixed:

Fixes #35113            

### Screenshots
| Before  | After  |
|---------|--------|
| <img width="400" height="500"
src="https://github.com/user-attachments/assets/319d97f0-a4b9-4b00-bc9a-670fd44fd86f"
/> | <img width="400" height="500" alt="After_31553"
src="https://github.com/user-attachments/assets/710a0fca-0c92-48fd-a91f-697d9e0d6b86"
/> |
…ible=false (#34621)

### Description

On Android, navigating from a page with the soft keyboard (IME) open to
a page with `Shell.NavBarIsVisible="False"` causes the destination page
to initially render under the status bar and then jump into the correct
position.

This behavior is more noticeable when the destination page performs
heavier UI work, and in some cases the layout may remain incorrectly
positioned.

### Root Cause

During `ShellRenderer.SwitchFragment`, the fragment transaction is
committed while the IME is still visible. Android continues to report
IME-related `WindowInsets`, causing the new layout to be measured with
incorrect top insets.

Once the IME state stabilizes, the layout is corrected, resulting in a
visible jump.

### Fix

Dismiss the soft keyboard before performing the fragment transaction:

- Detect IME visibility using `IsSoftInputShowing`
- Call `HideSoftInput()` prior to `FragmentTransaction`

This ensures that `WindowInsets` are stable before the new layout is
measured.

### Result

- Eliminates layout jump when navigating with keyboard open
- Ensures correct layout positioning from initial render
- Improves Shell navigation consistency on Android

### Testing

Added a UI test (`Issue34584`) that:

- Opens the keyboard by focusing an `Entry`
- Navigates to a page with `Shell.NavBarIsVisible="False"`
- Verifies that content is laid out below the status bar (`Y > 0`)

Note: The test validates final layout correctness, not visual animation.

### Related Issues

- Fixes #34584
- Related to #34060
… Shell (#35072)

<!-- Please let the below note in for people that 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 if this change resolves your issue.
Thank you!

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Issue Details:
#8296 - ContentPage.OnBackButtonPressed not invoked on iOS/MacCatalyst
when the native navigation bar back button is tapped inside a
NavigationPage.

#9095 - Shell.OnBackButtonPressed not invoked when the toolbar back
button is tapped on Android and iOS Shell pages

### Root Cause
#8296
- ShouldPopItem in NavigationRenderer.cs (the
navigationBar:shouldPopItem: UIKit delegate callback) fires when the
user taps the native iOS back button.
- Previously it unconditionally set _uiRequestedPop = true and returned
true, allowing the native pop without ever notifying MAUI's page model.
As a result, ContentPage.OnBackButtonPressed was never called on iOS
when the native back button was tapped inside a NavigationPage.

#9095 -  iOS (ShellSectionRenderer.cs)
- Same issue — tracker.Value.Page?.SendBackButtonPressed() skipped the
Shell chain and went directly to the ContentPage.

### Description of change

#8296  **NavigationRenderer.cs**
- In ShouldPopItem, call NavPage?.CurrentPage?.SendBackButtonPressed()
before allowing the native pop. If it returns true (the page
handled/cancelled back navigation), reset _uiRequestedPop and return
false to prevent the native pop.

#9095 **ShellSectionRenderer.cs** (iOS Shell)

- Route through _context.Shell?.SendBackButtonPressed() instead of
tracker.Value.Page?.SendBackButtonPressed(), so the Shell back button
tap goes through the same chain as the system back button.

**Note** on _sendPopPending = false in the BackButtonBehavior command
path: On iOS 26+, _sendPopPending is set to true unconditionally at the
start of SendPop(), before any BackButtonBehavior checks. When a
BackButtonBehavior.Command executes and returns false (preventing
navigation), ViewDidDisappear never fires — so without an explicit
reset, the flag stays true permanently and silently blocks all
subsequent back presses. The _sendPopPending = false after command
execution (line 188) is therefore an intentional and necessary fix to
prevent the back button becoming permanently unresponsive after a
command-handled back press on iOS 26+.

### Test results 
#### Shell — `OnBackButtonPressed` (fixes #9095)

| Platform | Navigation | `OnBackButtonPressed` |
|---|---|---|
| iOS / MacCatalyst | `GoToAsync` | ✅ Triggered |
| Android | `GoToAsync` | ✅ Triggered (app back button and emulator back
button) |
| Windows | `GoToAsync` | ✅ Triggered |

>`OnBackButtonPressed` is triggered for both the `Shell` and the
contained `ContentPage`.


#### NavigationPage — `OnBackButtonPressed` (fixes #8296)

| Platform | Navigation | `OnBackButtonPressed` | Notes |
|---|---|---|---|
| iOS / MacCatalyst | `PushAsync` | ✅ Triggered | |
| iOS / MacCatalyst | `PushModalAsync` | — | Back button not visible in
modal navigation |
| Android | `PushAsync` | ✅ Triggered (app back button and emulator back
button) | |
| Android | `PushModalAsync` | ✅ Triggered | Called on the modal
ContentPage |
| Windows | `PushAsync` | ✅ Triggered | |
| Windows | `PushModalAsync` | — | Back button not visible in modal
navigation |

> On Android and Windows, `OnBackButtonPressed` is triggered for both
the `NavigationPage` and the contained `ContentPage`.

#### TabbedPage — `OnBackButtonPressed`

| Platform | Navigation | `OnBackButtonPressed` | Notes |
|---|---|---|---|
| iOS / MacCatalyst | `PushAsync` | ✅ Triggered | |
| iOS / MacCatalyst | `PushModalAsync` | — | Back button not visible in
modal navigation |
| Android | `PushAsync` | ✅ Triggered | |
| Android | `PushModalAsync` | ✅ Triggered | |
| Windows | `PushAsync` | ✅ Triggered | |
| Windows | `PushModalAsync` | — | Back button not visible in modal
navigation |

#### FlyoutPage — `OnBackButtonPressed`

| Platform | Navigation | `OnBackButtonPressed` | Notes |
|---|---|---|---|
| iOS / MacCatalyst | `PushAsync` | ✅ Triggered | |
| iOS / MacCatalyst | `PushModalAsync` | — | Back button not visible in
modal navigation |
| Android | `PushAsync` | ✅ Triggered | |
| Android | `PushModalAsync` | ✅ Triggered | |
| Windows | `PushAsync` | ✅ Triggered | |
| Windows | `PushModalAsync` | — | Back button not visible in modal
navigation |


### Validated the behaviour in the following platforms
- [ ] Android
- [ ] Windows
- [x] iOS
- [x] Mac

### Issue Fixes
Fixes #8296 

### Screenshots
|  | Before  | After |
|--|---------|--------|
|8296|  <video
src="https://github.com/user-attachments/assets/13887369-e9e9-42df-a2a0-db88f0e6b38f">
|   <video
src="https://github.com/user-attachments/assets/d0ccfb01-59e8-44bc-8878-54c5d0f6fb7e"> 
|
|9095 |  <video
src="https://github.com/user-attachments/assets/664e0b7f-3964-4a1b-a4f6-46b1db758b48">
|   <video
src="https://github.com/user-attachments/assets/3ff159ec-93b0-4a91-854a-ca23211ff204"> 
|

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…s changed to default value (#35215)

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

<!-- Please let the below note in for people that 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 if this change resolves your issue.
Thank you!


<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Issue Details
On iOS/MacCatalyst, dynamically changing IndicatorView.IndicatorSize
back to the default value (6) at runtime has no visual effect —
indicators remain stuck at the previously set non-default size.

### Root Cause
The platform control has a hard-coded early return when the indicator
size equals the default value, which skips resetting the visual
transform even when indicators are currently scaled to a different size.
Additionally, the field tracking the last applied size was initialized
to -1 instead of the actual default.

### Description of Change
Replaced the hard-coded default value check with a comparison against
the last applied size, so the update is only skipped when the size is
truly unchanged. Initialized the tracking field to the default size to
correctly represent the initial state.
 

Validated the behavior in the following platforms
 
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac
 
### Issues Fixed
  
Fixes #35214 

### Output  ScreenShot

|Before|After|
|--|--|
| <video
src="https://github.com/user-attachments/assets/30f6d250-1a65-4061-986f-16d3940ac243"
>| <video
src="https://github.com/user-attachments/assets/759cc5af-9f5f-4d95-8b2a-262499928d0d">|
…ent) IsEnabled changed. (#31540)

### Issue Details:

The user has defined an implicit style for the BackgroundColor property
of a Grid, with the selected state value set to green. However, when the
IsEnabled property of the CollectionView's parent Grid is changed from
false to true immediately on the button click, the background color of
the currently selected item (which is also a Grid) is lost.
        
### Root Cause:

This happens because changing the IsEnabled property triggers the
ChangeVisualState() method in the base VisualElement class. As a result,
the visual state transitions to "Normal", overriding the previously
applied "Selected" state and its associated background color.

### Description of Change:

To address the issue, a selection check has been added to ensure that
the "Normal" state is not forced when the element is currently in the
"Selected" state. This change preserves the visual appearance of
selected items by preventing the "Selected" state from being overridden
during IsEnabled property changes.

**Tested the behavior in the following platforms.**

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

### Reference:

N/A

### Issues Fixed:

Fixes  #20615 

### Screenshots
| Before  | After  |
|---------|--------|
| <Video
src="https://github.com/user-attachments/assets/14ead580-bb70-4779-8c6e-00c8e7e1d425"
Width="300" Height="600"> | <Video
src="https://github.com/user-attachments/assets/d5699514-40e7-417b-b0c6-d22ebc101a91"
Width="300" Height="600"> |

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
### Description of Change

Fixed a small typo in Clipboard.shared.cs. Nothing exciting, really.

### Issues Fixed

Given that this is an extremely small typo fix only, I thought I'd just
go ahead and file a PR.

---------
<!-- 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. !!!!!!!
-->

This pull request fixes a regression where LinearGradientBrush with
transparent stops rendered as opaque black boxes on Android starting in
10.0.60. The fix preserves per-stop alpha values so gradients render
correctly.

### Root Cause : 

- Introduced by #31567 (Android drawable perf), which rewrote
MauiDrawable.Android.cs to use a Java-side PlatformDrawable.
- In that refactor, calls to GetGradientData were written as
GetGradientData(1.0f), which forces every gradient stop's alpha to fully
opaque (255), overriding any Transparent stop colors defined by the
developer.
  
### Description of Change
**Bug fix: Gradient transparency on Android**

* Updated `MauiDrawable.Android.cs` so that both linear and radial
gradient paints now call `GetGradientData(null)` instead of
`GetGradientData(1.0f)`, preserving per-stop alpha values for
backgrounds and borders. This prevents gradients with transparent stops
from rendering as solid black.
[[1]](diffhunk://#diff-9962b2ab4d4a0eb4922307e668bfe7d868c4fac7919a9463a3cba1859a6de86fL115-R115)
[[2]](diffhunk://#diff-9962b2ab4d4a0eb4922307e668bfe7d868c4fac7919a9463a3cba1859a6de86fL129-R129)
[[3]](diffhunk://#diff-9962b2ab4d4a0eb4922307e668bfe7d868c4fac7919a9463a3cba1859a6de86fL250-R250)
[[4]](diffhunk://#diff-9962b2ab4d4a0eb4922307e668bfe7d868c4fac7919a9463a3cba1859a6de86fL264-R264)

**Testing: New test case and UI test**

* Added a new issue test page `Issue35280` that displays an image with a
linear gradient overlay fading from black to transparent, to visually
confirm the fix.
* Introduced a corresponding UI test in `Issue35280.cs` to verify that
the gradient overlay is rendered correctly and not as an opaque black
box.

<!-- 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 #35280 
### Tested the behavior in the following platforms

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

| Before Issue Fix | After Issue Fix |
|----------|----------|
| <img width="1080" height="1920" alt="Screenshot_1777904296"
src="https://github.com/user-attachments/assets/a3ed29f1-9f85-44e7-9d4a-14e343aa8bda"
/> | <img width="1080" height="1920" alt="Screenshot_1777904172"
src="https://github.com/user-attachments/assets/c1f4be01-7af1-4e68-a36b-766ef167062f"
/> |
<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->
…acing is applied (#35309)

> [!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 if this change resolves your issue.
Thank you!

### Issue Details
On iOS, when an Editor has CharacterSpacing applied through a Slider,
the Editor becomes scrollable once the content exceeds its frame size.
After rotating the device (portrait → landscape → portrait), the Editor
loses scrollability because a re-measurement cascade expands it to the
full content height.

**Regression PR:** #30629
 
### Root Cause
PR #30629 added ValidateSafeArea() to MauiView.LayoutSubviews, which
calls InvalidateConstraintsCache() during rotation. This clears the
measurement cache (_lastMeasuredSize = null), causing HasBeenMeasured()
= false and needsMeasure = true for Pages.
As a result, a full re-measurement cascade occurs, where the Editor is
measured with infinite height. SizeThatFits then returns the full
content height (for example, 134px), causing the Editor to grow to fit
its content and lose its scrollable behavior.
 
### Description of Change
Updated EditorHandler.GetDesiredSize to cap the measured height to the
current frame height when the Editor content exceeds its frame
(scrollable state).
An AllowAutoGrowth flag was added to MauiTextView so Editors using
AutoSize = TextChanges are excluded from the cap and can continue
growing to fit their content.

### Issues Fixed
Fixes #35114

### Screenshots

| Before Issue Fix | After Issue Fix |
|----------|----------|
| <video width="300" height="600"
src="https://github.com/user-attachments/assets/4f1b08f7-abb2-40ae-84d8-f05cd063339c">
| <video width="300" height="600"
src="https://github.com/user-attachments/assets/42850642-087c-4198-91be-fc9b09b8dd43">
|
…ker.FocusChange (#29939)

Check if _editText is null before detaching the event.
)

<!-- Please let the below note in for people that 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 if this change resolves your issue.
Thank you!


<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Issue Details
VisualStateManager permanently breaks when attempting to set a control's
Style property during state transitions. When properties like IsEnabled
change, VSM automatically transitions states - but if that state
contains a Style setter, the control loses all VSM functionality and can
no longer respond to any state changes.

### Root Cause
The old code set the Style property by replacing the entire Style
object. This removed the original Style that contained the
VisualStateGroups attached property. Once the VSM attachment is lost,
the control cannot transition to other states - VSM is permanently
broken for that control.

### Description of Change
Added special handling when Setter values are Styles, using the
IStyle.Apply() and IStyle.UnApply() methods. Apply() applies the Style's
individual setters without replacing the Style property, keeping the VSM
connection intact. UnApply() properly removes the Style's setters when
the state changes, preventing conflicts between different states.

Validated the behavior in the following platforms
 
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac
 
### Issues Fixed
  
Fixes #17175  

### Output  ScreenShot

|Before|After|
|--|--|
| <video
src="https://github.com/user-attachments/assets/a5a2a482-73a2-4e84-a133-afacaf1c3872"
>| <video
src="https://github.com/user-attachments/assets/a1079f90-06cb-4083-8202-2517200b5346">|
…35208)

> [!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 if this change resolves your issue.
Thank you!

### Issue details
When a virtual XAML event handler is wired inside a DataTemplate (for
example, SwipeItem.Invoked) and the handler is defined in a base class
and overridden in a derived class, the app crashes in Release builds on
iOS/macOS and may also behave incorrectly on Android. This occurs due to
a bug in XamlC's IL code generator (SetPropertiesVisitor.cs), where the
ldvirtftn instruction receives the wrong vtable object (the anonymous
DataTemplate class instead of the root XAML element), causing runtime
failure with Full AOT compilation.

### Root Cause

The issue occurs because of incorrect IL generation in
SetPropertiesVisitor.ConnectEvent() when wiring a virtual event handler
inside a DataTemplate.

When XamlC compiles a DataTemplate, it generates an anonymous nested
class (e.g., <InitializeComponent>_anonXamlCDataTemplate_1) with a
LoadDataTemplate() method where event wiring happens. For virtual
handlers, XamlC must emit ldvirtftn, which requires the actual page
object as the vtable source to resolve the correct overridden method.

The bug was that the code always pushed Ldarg_0 as the vtable object.
Inside LoadDataTemplate(), Ldarg_0 is the anonymous class, not the root
page. This causes ldvirtftn to look up the virtual method on the wrong
vtable, so the override on the generic subclass is never found. On iOS
Full AOT, this causes a hard crash; on Android and Windows, the JIT
silently calls the base class method instead of the override.
 
### Description of Change

The fix involves replacing the extra Ldarg_0 push before ldvirtftn with
a Dup instruction, which reuses the delegate target object that is
already correctly loaded on the stack just above this code.

The delegate target (the root page) is already on the stack, correctly
resolved via context.Root for both the top-level and DataTemplate
contexts. Dup copies that same object for ldvirtftn, ensuring virtual
dispatch always targets the actual page's vtable, and the overridden
method on the generic subclass is found correctly on all platforms.
 
**Windows platform behavior:**
 
The issue does not occur on the Windows platform. Based on analysis,
even though Windows does not crash, the behavior before the fix was
technically undefined, as it relied on the JIT being lenient. If the
method resolution happened to pick the base class version instead of the
override, the logic would silently be incorrect without any error. The
fix makes the IL correct and explicit for all platforms.

Tested the behavior in the following platforms.
 
- [x] iOS
- [x] Mac
- [ ] Android
- [ ] Windows

### Issues Fixed

Fixes #18055

### Output

| Before Issue Fix | After Issue Fix |
|----------|----------|
| <video width="270" height="600"
src="https://github.com/user-attachments/assets/6bc99f45-7114-4ce5-9a75-d98d3c014882">
| <video width="270" height="600"
src="https://github.com/user-attachments/assets/00cd3e91-cb1b-4a9a-9df9-1a2538d2ec56">
|
…ding (#34845)

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->
### Issue Details
When set IsRefreshing = true in navigated page, refreshview is not
visible

### Root Cause
OnLoaded unsubscribed itself after firing once (refreshControl.Loaded -=
OnLoaded). So when the user navigated
back to the page, the Loaded event fired again but had no handler —
UpdateIsRefreshing() was never called, and
the refresh indicator never appeared.

### Description of Change

<!-- Enter description of the fix in this section -->
Removed Self-unsubscribe line refreshControl.Loaded -= OnLoaded so the
handler stays active across.

### 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 #30535 

<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->

**Tested the behavior in the following platforms.**
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac

| Before  | After  |
|---------|--------|
| **Windows**<br> <video
src="https://github.com/user-attachments/assets/408e35ed-61ed-4ad2-9104-f08635c98af2"
width="600" height="300"> | **Windows**<br> <video
src="https://github.com/user-attachments/assets/c16e311b-44c0-4571-af71-b3fa316fbea2"
width="600" height="300"> |
<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

<!-- Please let the below note in for people that 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 if this change resolves your issue.
Thank you!


<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Issue Details
Build fails with InvalidOperationException when using an empty (but
valid) SVG as the app icon. The SVG has width, height, and viewBox but
no drawn shapes inside.

### Root Cause
PR #33194 moved the size.IsEmpty check to run before both code paths in
DrawUnscaled, but size (from CullRect) is only needed in the downscale
path. Empty SVGs have a zero CullRect even with valid declared
dimensions, so the check incorrectly blocks the upscale path that never
uses size.

### Description of Change
Moved the size.IsEmpty check from before both branches into only the
else (downscale) branch where size is actually used. The scale >= 1 path
calls DrawPicture directly, which harmlessly draws nothing for empty
SVGs, producing a valid transparent image.
 

Validated the behavior in the following platforms
 
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac
 
### Issues Fixed
  
Fixes #35293 

### Output  ScreenShot

|Before|After|
|--|--|
| <video
src="https://github.com/user-attachments/assets/cf8040d6-9b0f-4867-bd4a-1713ea41d1d5"
>| <video
src="https://github.com/user-attachments/assets/97c09d5e-b2cc-4a13-b5a3-dc056dacba78">|
#32674)

<!-- Please let the below note in for people that 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 if this change resolves your issue.
Thank you!

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->
### Issue Details:

The FlowDirection property is not being applied to the EmptyView content
within a CollectionView.

### Root Cause
FlowDirection was not applied correctly to EmptyView because
EffectiveUserInterfaceLayoutDirection
returned incorrect values, causing RTL detection logic to fail. After
using the correct
property to update the isRTL boolean, the flip logic produced inverted
visuals and did not properly
propagate FlowDirection changes.

### Description of Change

- Replaced transform-based RTL handling with proper FlowDirection
propagation using the MAUI ItemsView.FlowDirection.
- For View-based and DataTemplate-based EmptyViews, the old
transform-based RTL handling was removed. The platform view now updates
its layout direction through UpdateFlowDirection().
- For string-based EmptyViews rendered as a UILabel, the text alignment
is set to center to provide a better user experience.

### Validated the behaviour in the following platforms
- [x] Android
- [x]  Windows
- [x] iOS
- [x] Mac

### Issues Fixed:

Fixes #32404 
Fixes #34522

### Screenshots
| Before  | After |
|---------|--------|
|  <video
src="https://github.com/user-attachments/assets/6423b8a9-8861-4a11-b825-00b4efa28fbb">
|   <video
src="https://github.com/user-attachments/assets/1c851a9b-e772-45ea-8fd5-485e081e53ed"> 
|
…g background (#34997)

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

<!-- Please let the below note in for people that 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 if this change resolves your issue.
Thank you!


<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Issue Details
On Android, switching from a gradient to a solid color is not worked —
the gradient persists visually.
On Windows, gradients are never applied, and setting Background to null
doesn't clear previously applied colors.

### Root Cause
On Android, BorderDrawable.SetBackground() doesn't clear the gradient
shader when switching to a solid color or null — the stale shader
persists on the underlying paint object.

On Windows,
[UpdateBackground()](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)
only handled
[SolidPaint](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html),
so gradients were ignored and null backgrounds didn't trigger resource
cleanup.

### Description of Change
On Android, clear the shader via platformPaint.SetShader(null) in
BorderDrawable.SetBackground() before applying the solid color.
On Windows, use
[button.Background?.ToPlatform()](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)
to handle all paint types and allow null to remove theme overrides.
Ensure
[RefreshThemeResources()](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)
always executes.

Validated the behavior in the following platforms
 
- [x] Android
- [x] Windows
- [ ] iOS
- [ ] Mac
 
### Issues Fixed
  
Fixes #34993  

### Output  ScreenShot
Android
|Before|After|
|--|--|
| <video
src="https://github.com/user-attachments/assets/a48e6fd4-46df-443e-90bf-c2ce41b3a000"
>| <video
src="https://github.com/user-attachments/assets/575b452a-9b68-4568-a5ec-ea14acce17c4">|


Windows
|Before|After|
|--|--|
| <video
src="https://github.com/user-attachments/assets/0b10cb79-2910-42ad-94e7-ef64283a8dc2"
>| <video
src="https://github.com/user-attachments/assets/74d41e8d-3734-4374-b7b7-b6e668234dfb">|
…Android in .NET 10 (#35295)

> [!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 if this change resolves your issue.
Thank you!

### Issue details
On Android (.NET MAUI 10), Shell toolbar colors are applied before
navigation completes during tab/page transitions, causing the current
page to briefly display the destination page’s colors. This is a
regression from .NET MAUI 9 and results in incorrect visual behavior
during navigation.

### Root Cause
The issue occurs because of the toolbar appearance update being
triggered before the tab navigation is fully completed when switching
tabs in a Shell with TabBar. During the tab change, the destination tab
colors are applied immediately while the previous tab content is still
visible on screen, which causes a brief color flash. This is especially
noticeable when different child pages use different toolbar colors. The
behavior started after an earlier change where the appearance update was
added during tab switching but executed before the section change was
committed.
 
### Description of Change
The fix involves changing the execution order so the section change is
committed first, and the appearance update happens only after the tab
switch is successfully accepted. This ensures the Shell internal state
is updated to the correct tab before applying the toolbar colors,
preventing premature color changes while the previous tab is still
visible. The update is also skipped when the tab switch is rejected or
cancelled, so colors continue to refresh correctly on every tab switch,
but now at the correct time.

### Why Tests were not added:

**Regarding the test case:** No automated test case was added for this
fix, as the issue is a brief visual color flash that occurs during the
tab-switch animation on Android and cannot be reliably captured through
the existing automated test infrastructure.
 
Screenshot-based tests cannot consistently capture the exact transition
frame where the issue occurs, and the current baseline comparison
approach is unable to accurately differentiate correct and incorrect
toolbar color timing during the animation.

Tested the behavior in the following platforms.
 
- [x] Android
- [ ] Mac
- [ ] iOS
- [ ] Windows

**Regression PR:** The PR
[25870](#25870) as the primary
regression source. PR [32882](#32882)
appears to be a later overlapping change affecting Shell color timing.

The PR [25870](#25870) as the primary
regression source. PR [32882](#32882)
appears to be a later overlapping change affecting Shell color timing.

### Issues Fixed

Fixes #35060

### Output

| Before Issue Fix | After Issue Fix |
|----------|----------|
| <video width="270" height="600"
src="https://github.com/user-attachments/assets/44ea19d0-7aca-42b1-b936-506eb4609f33">
| <video width="270" height="600"
src="https://github.com/user-attachments/assets/f1c8b6b4-44b5-4f6b-9daa-988daa33b90c">
|
Appears to be unused, but trips up analyzers when investigating other
issues.

Fixes: xamarin/Xamarin.Forms#1749

---------
<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Issue Details
In FlyoutPage, RTL FlowDirection is not working properly at initial and
runtime changes.

### Description of Changes
* Added an `UpdateFlowDirection` method to set the correct
`SemanticContentAttribute` on the root view, child controller views, and
navigation bar, ensuring proper mirroring for RTL layouts and correct
inheritance by child handlers.
* Updated property change handling to listen for `FlowDirection` changes
and trigger both `UpdateFlowDirection` and `UpdateLeftBarButton` when
flow direction is updated at runtime.
* Called `UpdateFlowDirection` during gesture recognizer setup to ensure
the correct flow direction is applied during initialization.

### 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 #34830 

<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->

**Tested the behavior in the following platforms.**
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac

| Before  | After  |
|---------|--------|
| **iOS**<br> <video
src="https://github.com/user-attachments/assets/f9a9cc1a-3320-4e8b-9c6c-3702c585b5c2"
width="300" height="600"> | **iOS**<br> <video
src="https://github.com/user-attachments/assets/7da0ba09-557f-46bd-81b7-2fed1295b61d"
width="300" height="600"> |
…dler disconnect (#35314)

> [!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 if this change resolves your issue.
Thank you!

### Description of Change

Fixes #27101.

When a `Page` is navigated away from on Windows, the focused control's
handler is disconnected.
`ElementHandler.IElementHandler.DisconnectHandler()` (in
`src/Core/src/Handlers/Element/ElementHandler.cs`) sets `PlatformView =
null` **before** running the platform-specific disconnect chain.

On Windows, that chain calls `UpdateIsFocused(false)`
(`src/Core/src/Handlers/View/ViewHandler.Windows.cs`), which then sets
`virtualView.IsFocused = false`. That property change cascades through:

```
BindableObject.SetValue
  → OnIsFocusedPropertyChanged
    → ChangeVisualState
      → VisualStateManager.GoToState
        → Setter.Apply (e.g. background color)
          → BindableObject.SetValue (mapped property)
            → Handler.UpdateValue("Background")
              → Property mapper
                → handler.PlatformView ← throws "PlatformView cannot be null here"
```

The strongly-typed `PlatformView` accessor (`ViewHandlerOfT.cs`,
`ElementHandlerOfT.cs`) throws `InvalidOperationException("PlatformView
cannot be null here")` because we already nulled it.

### Fix

Introduce a new `Disconnecting` state on `ElementHandlerState` and set
it for the duration of `DisconnectHandler(oldPlatformView)`.
`ElementHandler.UpdateValue` short-circuits when the handler is in that
state, so property fan-outs during teardown no longer hit the mapper
(and therefore no longer touch the released platform view).

The state is restored in a `finally` block so a throwing platform
disconnect cannot leave the handler stuck in `Disconnecting`.

Logical state on the `BindableObject` itself still gets updated by VSM
setters (so reused/rebound elements remain correct — when a recycled
element is reconnected, `SetVirtualView` re-pushes all current property
values via `_mapper.UpdateProperties`).

### Why fix here, not in `VisualElement.ChangeVisualState()` (or
`Page.cs`)?

Several controls override `ChangeVisualState()` and call
`VisualStateManager.GoToState` directly, bypassing the base
implementation (`Button`, `ImageButton`, `CheckBox`, `RadioButton`,
`Switch`). Guarding in `ChangeVisualState` would miss those paths, and a
naive `Handler is null` check would also regress legitimate pre-handler
XAML init scenarios (`VisualStateGroupsPropertyChanged`,
`VisualStateGroupList.OnStatesChanged`).

`ElementHandler.UpdateValue` is the central choke point that all
property cascades flow through, so the guard there:
- covers every code path on every platform,
- still lets VSM logical state settle on the `BindableObject`,
- requires no changes in any control-specific override.

### Tests

- **Unit test**:
`Microsoft.Maui.UnitTests.AbstractViewHandlerTests.UpdateValueIsSkippedWhileHandlerIsDisconnecting`
simulates the property fan-out from inside `DisconnectHandler` and
asserts the mapper is not invoked. Verified that the test fails on the
unmodified code (mapper count goes from 0 to 1) and passes after the
fix.
- **UI test**:
`Microsoft.Maui.TestCases.Tests.Issues.Issue27101.NoCrashWhenNavigatingBackFromPageWithFocusedButton`
repeatedly navigates a `NavigationPage` containing a focused `Button`
styled with VSM (Normal/Focused/Disabled/PointerOver/Pressed) to surface
the focus race.

### Relation to #27877

This PR supersedes #27877. That PR wrapped the post-disconnect
`ChangeVisualState` call in `try { ... } catch (ObjectDisposedException)
{ }` inside `Page.cs`. Two issues with that approach:
1. The actual exception thrown is `InvalidOperationException`, not
`ObjectDisposedException`, so the catch likely never fires for the
reported scenario (matches the unanswered review feedback from MartyIX
on 2025‑05‑30).
2. Even with the right exception type, that's a band-aid: it lets the
failing call happen, swallows the symptom, and only patches one of many
code paths that could trip the same issue (any subclass that triggers a
property change during disconnect).

### Issues Fixed

Fixes #27101
Supersedes #27877

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 2 pipeline(s).

<!-- 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. !!!!!!!
-->

### Description of Change
Reverts the iOS `ProgressBar` height-scaling behavior introduced in
#35507.
 
That PR wrapped `UIProgressView` in a container and vertically scaled it
to fill the MAUI-arranged height. While technically correct in
isolation, this changes the cross-platform behavior:
 
- **Before #35507**: A `ProgressBar` assigned a parent height of 200
occupies the allocated 200px layout area, but the ProgressBar _track_ is
rendered at its native default height — consistent across iOS, Android,
and Windows.
- **After #35507**: On iOS, the ProgressBar track is stretched to fill
the full 200px height, which does **not** match Android or Windows
behavior.
 
We also validated this in native iOS: when a height is assigned to the
parent container, `UIProgressView` renders at its default intrinsic
height and is **not** stretched — confirming that the previous MAUI
behavior was the correct cross-platform baseline.
 
 ### Impact
 
 - All existing iOS ProgressBar device tests are failing after #35507.
- The `ProgressBar_ProgressToMethod_VerifyVisualState` test visually
demonstrates the inconsistency (screenshots attached ).

 ### Screenshots
 
 | Platform | Before #35507 (expected) | After #35507 (regression) |
 |----------|--------------------------|---------------------------|
| iOS | <img width="1124" height="2286"
alt="ProgressBar_ProgressToMethod_VerifyVisualState"
src="https://github.com/user-attachments/assets/06b475ef-955a-4ad3-bdb7-99164a6b17f4"
/> | <img width="1124" height="2286"
alt="ProgressBar_ProgressToMethod_VerifyVisualState"
src="https://github.com/user-attachments/assets/444c9fa7-663d-416b-b95e-d7d01066c32f"
/> |
| Mac | <img width="789" height="563"
alt="ProgressBar_ProgressToMethod_VerifyVisualState (2)"
src="https://github.com/user-attachments/assets/aa89d1ec-cb19-4ed3-860a-1f326f2f100e"
/> | <img width="789" height="563"
alt="ProgressBar_ProgressToMethod_VerifyVisualState"
src="https://github.com/user-attachments/assets/0c068902-d8d9-4a74-b37d-c0e1f2a5f6fd"
/> |
| Windows | <img width="1010" height="729"
alt="ProgressBar_ProgressToMethod_VerifyVisualState"
src="https://github.com/user-attachments/assets/669aed20-11af-4b2b-b9b0-286bc68ddd8b"
/> | N/A |
| Android | <img width="1080" height="1735"
alt="ProgressBar_ProgressToMethod_VerifyVisualState (1)"
src="https://github.com/user-attachments/assets/679ade5f-2a30-4ac7-b2df-057d799ac1af"
/> | N/A |



cc : @AdamEssenmacher
<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->
@vishnumenon2684

Copy link
Copy Markdown
Contributor

/azp run maui-pr-uitests , maui-pr-devicetests

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 2 pipeline(s).

… not update the nav bar (#35896)

> [!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 if this change resolves your issue.
Thank you!


<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->
### Issue Details
In SR7, PR #30339 was reverted because Shell.NavBarIsVisible did not
work correctly in child page and value override scenarios. Therefore,
the PR changes are being reverted from the inflight/candidate branch.

### Description of Change

- Reverted PR #30339 in `inflight/Candidate`
- Reverted PR #34648 in `inflight/Candidate`
- Reverted the iOS 26 image from PR #34760 in `inflight/Candidate`

### Issues Fixed

Fixes #35249
@vishnumenon2684

Copy link
Copy Markdown
Contributor

/azp run maui-pr-uitests , maui-pr-devicetests

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 2 pipeline(s).

…inside modal (#35916)

<!-- Please let the below note in for people that 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 if this change resolves your issue.
  Thank you!
 
This is the same fix as #35803 (main) and #35768 (SR7 release branch).
Since the fix was not available in the inflight candidate branch, the
same change has been ported here to ensure consistent behaviour across
all active branches.
PureWeen pushed a commit that referenced this pull request Jun 15, 2026
When Get-ReleaseReadiness runs in -Candidate mode, the SR branch doesn't
exist yet, so 'Open PRs Targeting main' returns all 100 open PRs to main
— a noisy dump that buried the actually-useful signal (the candidate
promotion PR like 'June 8th, Candidate'). Observed live on #35867
(20.5KB report; most of it was that table).

In candidate mode the section now:
  - filters openSrPrs for titles matching /\bcandidate\b/i (case insensitive,
    word-boundary anchored so 'CandidateView' doesn't match)
  - emits a single bullet linking each candidate PR found, with author
    and updated date
  - links out to the full GitHub query for anyone who wants the full list
  - if no candidate PR is found, emits an explanatory note instead of
    silently dropping the section

Live SR mode (mode='shipped') is unchanged — backport PRs targeting an
actual release branch are a small useful set worth listing in full.
Get-PreviewReadiness is also unchanged; the user wants the preview
report to keep listing PRs.

Verified end-to-end on SR9: report shrank from 20.5KB → 2.8KB and
correctly surfaced #35716 ('June 8th, Candidate' by PureWeen).

Tests: 12 new (294 total) covering shipped-mode preservation, candidate
mode with no candidate PR, and candidate mode with a candidate PR found.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Vignesh-SF3580 and others added 2 commits June 15, 2026 21:58
…te branch (#35920)

> [!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 if this change resolves your issue.
Thank you!

### Issue Details
After PR #35309, the iOS snapshot for
EditorScrollingWhenEnclosedInBorder differs from the baseline by
approximately 1 px vertically. The Border outline, visible text lines,
and scroll thumb endpoints are all shifted by one pixel, causing the
exact-match snapshot comparison to fail.

**Test name:** EditorScrollingWhenEnclosedInBorder
**Cause PR:** #35309
 
### Root Cause
PR #35309 added a final cap in EditorHandler.GetDesiredSize that clamps
result.Height to heightConstraint. PR #35662 narrowed this behavior to
skip the SizeThatFits substitution path, but the cap was still applied
when the caller provided a finite heightConstraint (for example, when
Border measures its child).
base.GetDesiredSize correctly returned the requested size, but the final
cap reduced the calculated height to the Border's stroke-adjusted
constraint, resulting in a 1 px vertical drift.
 
### Description of Change
Added an else branch to the double.IsInfinity(...) check in
GetDesiredSize (iOS) to mark caller-provided finite constraints using
heightSubstitutedFromSizeThatFits = true.
The final height cap now applies only when the height value was
substituted internally, restoring the standard MAUI measure behavior for
caller-provided constraints while preserving the existing behavior.

### Output
| Before Issue Fix | After Issue Fix |
|----------|----------|
| <img width="350" height="110"
src="https://github.com/user-attachments/assets/4f3d5b68-7931-4599-a869-b07c7e3bd521">
| <img width="350" height="110"
src="https://github.com/user-attachments/assets/b3c883a5-0c3d-41bd-8fc6-9d127def72b9">
|
…test failures on candidate branch (#35923)

<!-- Please let the below note in for people that 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 if this change resolves your issue.
  Thank you!

## Root Cause

PR #34699 introduced `_cachedImageSize` to eliminate timing-dependent
behavior in `GetDesiredSize()`. As part of that change,
`MapSourceAsync()` resets the cache to `Zero` whenever a new image
source is assigned.

However, `GetDesiredSize()` was updated to rely exclusively on
`_cachedImageSize` and no longer considered the live decoded size
available on `BitmapSource`. This created a timing gap where WinUI had
already completed image decoding and populated
`BitmapSource.PixelWidth`/`PixelHeight`, but the asynchronous
`ImageOpened` event had not yet fired to update the cache.

If a layout pass occurred during this window, `GetDesiredSize()`
observed a zero-sized cache, skipped the natural-size constraint, and
allowed the image to expand to the available container size instead of
respecting its decoded pixel dimensions.

## Description of Change

Two minimal updates were made in `ImageHandler.Windows.cs`:

`GetDesiredSize()
`
* Reads the live decoded size from `BitmapSource` first.
* Falls back to `_cachedImageSize` only when the live size is not yet
available.
* Aligns with the existing live-first, cache-fallback pattern already
used in `UpdatePlatformMaxConstraints()`.

`GetImageSize()
`
* Added a null-conditional guard for `PlatformView` to prevent a
potential null-reference exception when `GetDesiredSize()` is called
after handler disconnection.

## Regression Introduced By
PR #34699 
 
### Issues Fixed
Fixes the following candidate branch regressions:
In `Issue30403SmallImages.cs` file:
`ConstrainedContainers_ShouldHandleSmallImages` 
`SmallImageEndAlignment_ShouldRespectAlignment`
`SmallImageInLargeContainer_ShouldNotExceedIntrinsicSize`
`SmallImageStartAlignment_ShouldRespectAlignment`
`SizeComparison_ShouldShowDifferentSizes`
`TinyImage_ShouldRemainTiny` 
 
Tested the behaviour in the following platforms
- [ ] Android
- [x] Windows
- [ ] iOS
- [ ] Mac
### Issue Details
Due to PR #34630, some shell tests are failed in the June 8 Candidate

### Description of changes
Replaced AddDisplayedPageObserver with per-ShellContent PropertyChanged
subscription filtered to ShellContent.ContentProperty only (same pattern
used on iOS). This fires only when the page content actually changes,
never on tab switches. Event subscriptions are managed across
SetVirtualView, OnItemsCollectionChanged, and DisconnectHandler to
handle dynamic tab additions/removals.

### Failed test case
* ObservableCollectionChangeListView 
* NoDuplicateTitleViews[Shell]
* NoDuplicateTitleViews[TitleView]
* NavigatingBackAndForthDoesNotCrash
* NavigatingBackToAlreadySelectedTopTabDoesntCrash
* ShellNavigationFeatureTests - **All test cases except first 3**
* ShellItemItemsClearTests 
* ShellColorsResetOnNavigation 
* TabBarVisibilityShowsOnPage2UsingBinding 
* TabBarVisibilityHidesOnPage2UsingBindingn 
* NavBarUpdatesWhenSwitchingShellContent 
* HideActiveShellContent
* UpdateSearchHandlerMenuItemForTabNavigation
…es (#35940)

<!-- Please let the below note in for people that 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 if this change resolves your issue.
Thank you!

### Issue Details
- This PR reverts two chained Android safe area fixes that together
introduced regressions on the `inflight/candidate` branch:

**#[35555](#35555) — Fix Android
Shell top inset when nav bar is hidden**
- #35555 calls `ViewCompat.RequestApplyInsets()` synchronously inside
`ToolbarExtensions.UpdateIsVisible` — before the layout pass runs. At
that moment, `GetLocationOnScreen` returns the content view's stale
pre-collapse position, which makes `SafeAreaExtensions` think the view
is already safely below the status bar and zeros the top inset. When the
layout pass then runs and the AppBar collapses, the content moves to
`y=0` with `paddingTop=0` — rendering behind the status bar.
 
 This timing issue caused 3 UI snapshot test failures:
 - `ShellPages_NavBarVisibilityHide`
 - `VerifyNavBarStatusAtRuntime`
 - `ToggleHasNavigationBar_HidesBar_Visual`
 
**#35819 — Fix ShellPages_NavBarVisibilityHide,
VerifyNavBarStatusAtRuntime, and ToggleHasNavigationBar_HidesBar_Visual
test failures**
 
- #35819 attempted to fix the above 3 failures by caching the AppBar's
visibility state as `AppBarHasContent` on `MauiWindowInsetListener` and
using it as a guard in `SafeAreaExtensions.cs` — preserving `top` inset
when the AppBar is confirmed hidden, and zeroing it when the AppBar is
confirmed visible. This resolved the 3 test failures, but the
`AppBarHasContent != false` guard is too broad: it fires for **all views
on any page where the AppBar is hidden**, not just the stale Shell root
content view it was designed to protect. This introduced 8 new Android
UI snapshot regressions:
 - `EditorRuntimeTextAlignmentChanged`
 - `EditorPlaceholderRuntimeTextAlignmentChanged`
 - `VerifyLabelBackgroundIsClippedWithRectangleGeometry`
 - `TransparentShapeShouldNotDisplayShadow`
 - `TabBarShouldBeVisibleAfterNavigatingFromModalViaGoToAsync`
 - `VerifySwitchControlSize`
 - `CreateStackWithPadding`
 - `ModalNavigationShouldNotHang`
 
 ### Reason
 
- The fundamental issue is a race between `RequestApplyInsets()`
dispatch and the layout pass. #35555 introduced the race; #35819
attempted to work around it via an `AppBarHasContent` state cache, but
the guard scope is too wide — it applies `paddingTop=statusBarHeight` to
unrelated child views (e.g., centered `StackLayout`, `Editor`, overlays)
that happen to be visible when the AppBar is hidden, producing incorrect
offsets across a wide range of layout scenarios.
- Reverting both PRs to restore the stable pre-#35555 baseline while a
correct fix is designed.
 
 ### Changes
 
**From #35819** (`MauiWindowInsetListener.cs`, `SafeAreaExtensions.cs`):
- Removed `AppBarHasContent` nullable bool property and
`SetAppBarContentState` method
- Removed `SetAppBarContentState` dispatch call from
`ApplyDefaultWindowInsets`
 - Removed `AppBarHasContent = null` reset on navigation
- Removed `AppBarHasContent == true` guard in the `overlap` branch of
`ApplyAdjustedSafeAreaInsetsPx`
- Removed `AppBarHasContent != false` guard in the `below-safe` branch
of `ApplyAdjustedSafeAreaInsetsPx`
 
**From #35555** (`ToolbarExtensions.cs`, `MauiWindowInsetListener.cs`,
device tests):
- Replaced `HasVisibleAppBarContent()` with the original simple inline
`MeasuredHeight > 0` check
- Removed smart `RequestApplyInsets` chain (CoordinatorLayout →
AppBarLayout → toolbar fallback);
   reverted to simple `ViewCompat.RequestApplyInsets(nativeToolbar)`
- Removed device tests:
`HiddenShellNavigationBarClearsAppBarInsetPadding` and
   `PushingToPageWithoutNavigationBarClearsAppBarInsetPadding`
- Removed test helpers `CreateTopCutoutInsets`, `AssertTopInsets`,
`AttachCapturingWindowInsetsListener`,
   and `CapturingWindowInsetsListener`

@kubaflo kubaflo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Roll-up PR — CI status note

This is a "Candidate" roll-up PR (100 commits, 100 files) for the June 8th release train. Per review policy, roll-up PRs receive a CI status note rather than line-by-line review.

CI Status

44 non-passing checks (excluding pass/success/skipped).

This PR requires manual review and CI investigation by the release team.


Review conducted by: @kubaflo's autonomous multi-model review loop
Timestamp: 2026-06-17T19:30Z

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.