diff --git a/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellRenderer.cs b/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellRenderer.cs index 079585280840..92e2830e31f4 100644 --- a/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellRenderer.cs +++ b/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellRenderer.cs @@ -6,6 +6,7 @@ using Android.Graphics.Drawables; using Android.Views; using Android.Widget; +using Microsoft.Maui.Platform; using AndroidX.DrawerLayout.Widget; using AndroidX.Fragment.App; using Microsoft.Maui.ApplicationModel; @@ -218,6 +219,13 @@ protected virtual void OnElementSet(Shell shell) protected virtual void SwitchFragment(FragmentManager manager, AView targetView, ShellItem newItem, bool animate = true) { + var rootView = _flyoutView?.AndroidView; + + if (rootView != null && rootView.IsSoftInputShowing()) + { + rootView.HideSoftInput(); + } + var previousView = _currentView; _currentView = CreateShellItemRenderer(newItem); _currentView.ShellItem = newItem; diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue34584.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue34584.cs new file mode 100644 index 000000000000..9c7d3657efbb --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue34584.cs @@ -0,0 +1,74 @@ +namespace Maui.Controls.Sample.Issues; + +[Issue(IssueTracker.Github, 34584, "Content renders under status bar when navigating with keyboard open to a page with NavBarIsVisible=False", PlatformAffected.Android)] +public class Issue34584 : TestShell +{ + protected override void Init() + { + var mainPage = new Issue34584_MainPage(); + var destinationPage = new Issue34584_DestinationPage(); + + AddContentPage(mainPage, "MainPage"); + AddContentPage(destinationPage, "DestinationPage"); + } +} + +public class Issue34584_MainPage : ContentPage +{ + public Issue34584_MainPage() + { + var entry = new Entry + { + Placeholder = "Tap here to open keyboard", + AutomationId = "Entry" + }; + + var navigateButton = new Button + { + Text = "Navigate", + AutomationId = "NavigateButton" + }; + + entry.Completed += async (s, e) => + { + await Shell.Current.GoToAsync("//DestinationPage", false); + }; + + Content = new VerticalStackLayout + { + Spacing = 20, + Padding = new Thickness(0), + Children = + { + new Label + { + Text = "Main Page - Tap entry, type text, then navigate", + FontSize = 18 + }, + entry, + navigateButton + } + }; + } +} + +public class Issue34584_DestinationPage : ContentPage +{ + public Issue34584_DestinationPage() + { + Shell.SetNavBarIsVisible(this, false); + + Content = new VerticalStackLayout + { + Children = + { + new Label + { + Text = "Destination Page", + FontSize = 24, + AutomationId = "TargetLabel" + } + } + }; + } +} diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34584.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34584.cs new file mode 100644 index 000000000000..b0638f7d3714 --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34584.cs @@ -0,0 +1,57 @@ +#if ANDROID +using NUnit.Framework; +using UITest.Appium; +using UITest.Core; + +namespace Microsoft.Maui.TestCases.Tests.Issues; + +public class Issue34584 : _IssuesUITest +{ + public Issue34584(TestDevice testDevice) : base(testDevice) + { + } + + public override string Issue => "Content renders under status bar when navigating with keyboard open to a page with NavBarIsVisible=False"; + + [Test] + [Category(UITestCategories.Shell)] + public void ContentShouldNotRenderUnderStatusBarAfterNavigatingWithKeyboardOpen() + { + // Wait for the main page + App.WaitForElement("Entry"); + + // Open keyboard + App.Tap("Entry"); + App.EnterText("Entry", "test"); + + // Navigate while keyboard is open + App.PressEnter(); + + // Wait for destination page + App.WaitForElement("TargetLabel"); + + // Poll for a short period to detect transient layout issues during navigation + bool foundInvalidPosition = false; + + var start = DateTime.UtcNow; + var timeout = TimeSpan.FromSeconds(1); + + while (DateTime.UtcNow - start < timeout) + { + var rect = App.FindElement("TargetLabel").GetRect(); + + // Small threshold to account for device differences + if (rect.Y < 5) + { + foundInvalidPosition = true; + break; + } + + System.Threading.Thread.Sleep(50); + } + + Assert.That(foundInvalidPosition, Is.False, + "TargetLabel was temporarily rendered under the status bar"); + } +} +#endif \ No newline at end of file