Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -130,42 +130,61 @@ public override WindowInsetsCompat OnApplyWindowInsets(AView v, WindowInsetsComp
if (insets == null || v == null)
return insets;

if (v is CoordinatorLayout)
if (FlyoutView is IHandleWindowInsets handleWindowInsets)
{
return base.OnApplyWindowInsets(v, insets);
}

if (v is CoordinatorLayout && FlyoutView is not null)
{
// The flyout overlaps the status bar so we don't really care about insetting it
var systemBars = insets.GetInsets(WindowInsetsCompat.Type.SystemBars());
var displayCutout = insets.GetInsets(WindowInsetsCompat.Type.DisplayCutout());
var topInset = Math.Max(systemBars?.Top ?? 0, displayCutout?.Top ?? 0);
var bottomInset = Math.Max(systemBars?.Bottom ?? 0, displayCutout?.Bottom ?? 0);
var leftInset = Math.Max(systemBars?.Left ?? 0, displayCutout?.Left ?? 0);
var appbarLayout = v.FindDescendantView<AppBarLayout>((v) => true);

int flyoutViewBottomInset = 0;

if (FooterView is not null)
{
v.SetPadding(0, 0, 0, bottomInset);
flyoutViewBottomInset = 0;
if (appbarLayout.MeasuredHeight > 0)
{
// When AppBarLayout exists, let it handle the top inset
v.SetPadding(leftInset, 0, 0, bottomInset);
appbarLayout?.SetPadding(0, topInset, 0, 0);
}
else
{
// No AppBarLayout, root view handles top inset
v.SetPadding(leftInset, topInset, 0, bottomInset);
appbarLayout?.SetPadding(0, 0, 0, 0);
}
}
else
{
flyoutViewBottomInset = bottomInset;
v.SetPadding(0, 0, 0, 0);
if (appbarLayout.MeasuredHeight > 0)
{
// When AppBarLayout exists, let it handle the top inset
v.SetPadding(leftInset, 0, 0, 0);
appbarLayout?.SetPadding(0, topInset, 0, 0);
}
else
{
// No AppBarLayout, root view handles top inset
v.SetPadding(leftInset, topInset, 0, 0);
appbarLayout?.SetPadding(0, 0, 0, 0);
}
}

if (appbarLayout.MeasuredHeight > 0)
{
FlyoutView?.SetPadding(0, 0, 0, flyoutViewBottomInset);
appbarLayout?.SetPadding(0, topInset, 0, 0);
}
else
{
FlyoutView?.SetPadding(0, topInset, 0, flyoutViewBottomInset);
appbarLayout?.SetPadding(0, 0, 0, 0);
}
FlyoutView.SetPadding(0, 0, 0, flyoutViewBottomInset);

if (_bgImageRef != null && _bgImageRef.TryGetTarget(out var bgImage) && bgImage != null)
{
bgImage.SetPadding(0, topInset, 0, bottomInset);
bgImage.SetPadding(leftInset, topInset, 0, bottomInset);
}

return WindowInsetsCompat.Consumed;
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

is this screen shot correct? should there be this much space between the navigation bar and the flyout items?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes @PureWeen , If the flyout items contains images or icons, they would render fine.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
42 changes: 42 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue32275.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
namespace Maui.Controls.Sample.Issues;

[Issue(IssueTracker.Github, 32275, "[NET10] SafeAreaEdges cannot be set for Shell and the flyout menu collides with display notch and status bar in landscape mode", PlatformAffected.Android)]
public class Issue32275 : TestShell
{
protected override void Init()
{
FlyoutBehavior = FlyoutBehavior.Flyout;

for (int i = 0; i < 10; i++)
{
Items.Add(new FlyoutItem
{
Title = "Issue 32275",
Items =
{
new ShellContent
{
Content = new Issue32275ContentPage(),
}
}
});
}
}

public class Issue32275ContentPage : TestContentPage
{
protected override void Init()
{
Title = "Issue 32275";
Content = new StackLayout
{
Children =
{
new Label { AutomationId = "Issue32275Label", Text = "Open the flyout menu in landscape mode on a device with a display notch or status bar. The flyout menu should not collide with the notch or status bar." }
}
};
}
}
}


49 changes: 49 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue32275_Template.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
namespace Maui.Controls.Sample.Issues;

[Issue(IssueTracker.None, 32275, "SafeAreaEdges should be handled by the FlyoutContentTemplate", PlatformAffected.Android)]
public class Issue32275_Template : TestShell
{
protected override void Init()
{
FlyoutBehavior = FlyoutBehavior.Flyout;

var page = new Issue32275_Template_ContentPage();

AddFlyoutItem(page, "Flyout Item");


FlyoutContentTemplate = new DataTemplate(() =>
{
var stackLayout = new StackLayout() { BackgroundColor = Colors.Gray, SafeAreaEdges = SafeAreaEdges.All };

for (int i = 0; i < 50; i++)
{
var label = new Label
{
Text = $"Flyout Item {i + 1}",
FontSize = 24,
};

stackLayout.Children.Add(label);
}
return stackLayout;
});
}

public class Issue32275_Template_ContentPage : TestContentPage
{
protected override void Init()
{
Title = "Issue 32275";
Content = new StackLayout
{
Children =
{
new Label { AutomationId = "Issue32275_Template_Label", Text = "Open the flyout menu in landscape mode on a device with a display notch or status bar. The flyout menu should not collide with the notch or status bar. The default SafeAreaPadding should not be applied. It should be handled by the template itself." }
}
};
}
}
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#if TEST_FAILS_ON_CATALYST && TEST_FAILS_ON_WINDOWS // Ignore file for Catalyst and Windows platforms. This test is applicable for mobile platforms only.
Comment thread
PureWeen marked this conversation as resolved.
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.TestCases.Tests.Issues;

public class Issue32275 : _IssuesUITest
{
public Issue32275(TestDevice testDevice) : base(testDevice)
{
}

public override string Issue => "[NET10] SafeAreaEdges cannot be set for Shell and the flyout menu collides with display notch and status bar in landscape mode";

[Test]
[Category(UITestCategories.SafeAreaEdges)]
public void ShellFlyoutShouldRespectSafeArea()
Comment thread
jsuarezruiz marked this conversation as resolved.

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.

This test is failing on iOS:

at UITest.Appium.AppiumQuery.GetQueryBy(String token, String value) in /_/src/TestUtils/src/UITest.Appium/AppiumQuery.cs:line 198
   at UITest.Appium.HelperExtensions.Wait(Func`1 query, Func`2 satisfactory, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2557
   at UITest.Appium.HelperExtensions.WaitForElement(IApp app, String marked, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency, Nullable`1 postTimeout) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 745
   at UITest.Appium.HelperExtensions.WaitForFlyoutIcon(IApp app, String automationId, Boolean isShell) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2263
   at UITest.Appium.HelperExtensions.TapFlyoutIcon(IApp app, String title, Boolean isShell, Boolean waitForFlyoutIcon) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2336
   at UITest.Appium.HelperExtensions.TapFlyoutPageIcon(IApp app, String title) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2378
   at Microsoft.Maui.TestCases.Tests.Issues.Issue32275.ShellFlyoutShouldRespectSafeArea() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue32275.cs:line 22
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)

{
App.WaitForElement("Issue32275Label");
App.SetOrientationLandscape();
App.TapShellFlyoutIcon();
#if ANDROID
VerifyScreenshot(cropLeft: 125);
#else
VerifyScreenshot();
#endif
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#if TEST_FAILS_ON_CATALYST && TEST_FAILS_ON_WINDOWS // Ignore file for Catalyst and Windows platforms. This test is applicable for mobile platforms only.
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.TestCases.Tests.Issues;

public class Issue32275_Template : _IssuesUITest
{
public Issue32275_Template(TestDevice testDevice) : base(testDevice)
{
}

public override string Issue => "SafeAreaEdges should be handled by the FlyoutContentTemplate";

[Test]
[Category(UITestCategories.SafeAreaEdges)]
public void ShellFlyoutContentTemplateShouldRespectSafeArea()
{
App.WaitForElement("Issue32275_Template_Label");
App.TapShellFlyoutIcon();
App.SetOrientationLandscape();
Thread.Sleep(1000); // Allow time for orientation change to take effect and UI to stabilize.
#if ANDROID
VerifyScreenshot(cropLeft: 125);
#else
VerifyScreenshot();
#endif
}
}
#endif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading