Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1595,6 +1595,38 @@ public override void ViewWillTransitionToSize(SizeF toSize, IUIViewControllerTra
UpdateLeftBarButtonItem();
}

public override void TraitCollectionDidChange(UITraitCollection previousTraitCollection)
{
base.TraitCollectionDidChange(previousTraitCollection);

// Check if orientation changed (size class transition)
if (previousTraitCollection?.VerticalSizeClass != TraitCollection.VerticalSizeClass ||
previousTraitCollection?.HorizontalSizeClass != TraitCollection.HorizontalSizeClass)
{
if (OperatingSystem.IsIOSVersionAtLeast(26) || OperatingSystem.IsMacCatalystVersionAtLeast(26))
{
UpdateTitleViewFrameForOrientation();
}
}
}

/// iOS 26+ requires autoresizing masks (UIViewAutoresizing.FlexibleWidth) During orientation changes, the autoresizing mask
Comment thread
jfversluis marked this conversation as resolved.
/// automatically adjusts the width, but we need to explicitly update the frame to ensure the
/// title view uses the full available width from the navigation bar. Without this update,
/// the title view may not properly expand to fill the navigation bar after rotation.
void UpdateTitleViewFrameForOrientation()
{
if (NavigationItem?.TitleView is not UIView titleView)
return;

if (!_navigation.TryGetTarget(out NavigationRenderer navigationRenderer))
return;

var navigationBarFrame = navigationRenderer.NavigationBar.Frame;
titleView.Frame = new RectangleF(0, 0, navigationBarFrame.Width, navigationBarFrame.Height);
titleView.LayoutIfNeeded();
}

internal void UpdateLeftBarButtonItem(Page pageBeingRemoved = null)
{
NavigationRenderer n;
Expand Down
41 changes: 41 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue32722.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Maui.Controls.Sample.Issues.Issue32722"
Title="Issue 32722">

<NavigationPage.TitleView>
<Grid x:Name="TitleViewGrid"
BackgroundColor="LightBlue"
HorizontalOptions="FillAndExpand"
AutomationId="TitleViewGrid">
<Label Text="TitleView Test"
x:Name="TitleLabel"
AutomationId="TitleLabel"
TextColor="White"
FontSize="18"
FontAttributes="Bold"
VerticalOptions="Center"
HorizontalOptions="Center"/>
</Grid>
</NavigationPage.TitleView>

<VerticalStackLayout Padding="20" Spacing="10">
<Label Text="Issue #32722 Test"
FontSize="20"
FontAttributes="Bold"
AutomationId="HeaderLabel"
HorizontalOptions="Center"/>

<Label Text="This test verifies that NavigationPage.TitleView expands when the window/orientation changes on iOS 26+."
FontSize="14"
AutomationId="DescriptionLabel"/>

<Label x:Name="StatusLabel"
Text="Rotate device to test"
AutomationId="StatusLabel"
FontSize="16"
TextColor="Gray"
Margin="0,20,0,0"/>
</VerticalStackLayout>
</ContentPage>
17 changes: 17 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue32722.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Maui.Controls.Sample.Issues;

[Issue(IssueTracker.Github, 32722, "NavigationPage.TitleView does not expand with host window in iPadOS 26+", PlatformAffected.iOS)]
public class Issue32722NavPage : NavigationPage
{
public Issue32722NavPage() : base(new Issue32722())
{
}
}

public partial class Issue32722 : ContentPage
{
public Issue32722()
{
InitializeComponent();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.TestCases.Tests.Issues
{
public class Issue32722 : _IssuesUITest
{
public override string Issue => "NavigationPage.TitleView does not expand with host window in iPadOS 26+";

public Issue32722(TestDevice device) : base(device) { }

[Test]
[Category(UITestCategories.Navigation)]
public void TitleViewExpandsOnRotation()
{
// Wait for page to load
App.WaitForElement("TitleViewGrid");
App.WaitForElement("StatusLabel");

// Get initial orientation and TitleView bounds
var titleViewInitial = App.WaitForElement("TitleViewGrid").GetRect();
var initialWidth = titleViewInitial.Width;

App.SetOrientationLandscape();

// Wait for rotation to complete
System.Threading.Thread.Sleep(2000);

Copilot AI Nov 23, 2025

Copy link

Choose a reason for hiding this comment

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

Using Thread.Sleep in tests is a brittle practice. Consider using a proper wait mechanism that checks for the condition to be met, or use the test framework's built-in wait utilities with a timeout. This would make the test more reliable and potentially faster.

Copilot uses AI. Check for mistakes.

// Get TitleView bounds after rotation
var titleViewAfterRotation = App.WaitForElement("TitleViewGrid").GetRect();
var newWidth = titleViewAfterRotation.Width;

// On iOS 26+, the TitleView should expand/contract with the rotation
// The bug was that it would stay at the original width
// After fix, the width should change to match the new navigation bar width
Assert.That(newWidth, Is.Not.EqualTo(initialWidth).Within(100),
"TitleView width should change after rotation");

// Verify TitleView is still visible and has reasonable dimensions
Assert.That(newWidth, Is.GreaterThan(100),
"TitleView should have a reasonable width after rotation");

// Rotate back to original orientation
App.SetOrientationPortrait();
System.Threading.Thread.Sleep(2000);

// Verify TitleView returns to approximately original width
var titleViewFinal = App.WaitForElement("TitleViewGrid").GetRect();
Assert.That(titleViewFinal.Width, Is.EqualTo(initialWidth).Within(5),
"TitleView should return to original width after rotating back");
}
Comment on lines +46 to +52

Copilot AI Nov 23, 2025

Copy link

Choose a reason for hiding this comment

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

Using Thread.Sleep in tests is a brittle practice. Consider using a proper wait mechanism that checks for the condition to be met, or use the test framework's built-in wait utilities with a timeout. This would make the test more reliable and potentially faster.

Suggested change
System.Threading.Thread.Sleep(2000);
// Verify TitleView returns to approximately original width
var titleViewFinal = App.WaitForElement("TitleViewGrid").GetRect();
Assert.That(titleViewFinal.Width, Is.EqualTo(initialWidth).Within(5),
"TitleView should return to original width after rotating back");
}
WaitForTitleViewWidth("TitleViewGrid", initialWidth, tolerance: 5, timeoutMs: 3000);
// Verify TitleView returns to approximately original width
var titleViewFinal = App.WaitForElement("TitleViewGrid").GetRect();
Assert.That(titleViewFinal.Width, Is.EqualTo(initialWidth).Within(5),
"TitleView should return to original width after rotating back");
}
/// <summary>
/// Waits until the TitleView's width is within the specified tolerance of the expected value, or until timeout.
/// </summary>
private void WaitForTitleViewWidth(string automationId, double expectedWidth, double tolerance, int timeoutMs)
{
var start = DateTime.UtcNow;
while ((DateTime.UtcNow - start).TotalMilliseconds < timeoutMs)
{
var rect = App.WaitForElement(automationId).GetRect();
if (Math.Abs(rect.Width - expectedWidth) <= tolerance)
return;
System.Threading.Thread.Sleep(100);
}
// Final check after timeout
var finalRect = App.WaitForElement(automationId).GetRect();
if (Math.Abs(finalRect.Width - expectedWidth) > tolerance)
{
Assert.Fail($"TitleView width did not return to expected value within {timeoutMs}ms. Expected: {expectedWidth}, Actual: {finalRect.Width}");
}
}

Copilot uses AI. Check for mistakes.
}
}
Loading