dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
21.63k stars 1.62k forks source link

[iOS] `FlyoutPage` secondary toolbar items covers `Detail` content on iOS #22077

Open bzd3y opened 2 weeks ago

bzd3y commented 2 weeks ago

Description

When FlyoutPage.Detail is a NavigationPage with a child page that has toolbar items, the Secondary toolbar items cover the contents of the child page at the top.

This is possibly related to #14559, in that it concerns displaying the Secondary toolbar items. That bug is about them not displaying as Secondary in a non-FlyoutPage. The toolbar items actually display "correctly" on a FlyoutPage as far as being on their own row, but they cover up the page content at the top.

There is also another possibly related bug, where if you push another NavigationPage then the navigation bars/toolbar items stack on top of each other on each subsequent page. You can see this by clicking the "Test" button in the reproduction project. Note that when this happens, the content of the page is correctly not hidden behind the toolbars.

I realized that the above is because I was pushing another actual NavigationPage which "works" but probably isn't correct.

Finally, neither ToolbarHandler.Mapping.PrependToMapping or AppendToMapping seem to run in iOS (same for NavigationViewHandler). I thought maybe that was the problem, but looking at the code it looks like iOS doesn't use the mappers like Android does. Things like the ToolbarHandler and NavigationViewHandler don't seem to be implemented for iOS, but I may not be following the code correctly.

I will also note here that when not using a FlyoutPage then the "Test" button crashes on iOS but works on Android. But I think this is a separate issue so I'm going to make a separate bug issue for it assuming I don't find an existing issue.

Steps to Reproduce

  1. Clone the reproduction project here: https://github.com/bzd3y/ReproductionProject.git
  2. Run the Toolbars project on iOS
  3. Observe that the item with text "One" in the ListView is hidden behind the Secondary toolbar items.
  4. Also, clicking the "Test" button in the toolbar will push another page and the navigation bars/toolbars will stack.

Link to public reproduction project repository

https://github.com/bzd3y/ReproductionProject.git

Version with bug

8.0.7 SR2

Is this a regression from previous behavior?

Yes, this used to work in Xamarin.Forms

Last version that worked well

Unknown/Other

Affected platforms

iOS

Affected platform versions

iOS 17

Did you find any workaround?

I have not found any workarounds. I tried looking at using a handler to figure out what is going on and maybe fix it, but so far I haven't been successful.

Relevant log output

No response

bzd3y commented 1 week ago

It appears that the cause of this is that this combination of views is not set to use the iOS "SafeArea". Using the following handler seems to solve the problem:

PageHandler.Mapper.PrependToMapping("ToolbarFix", (h, v) =>
{
    if (v is Page page && page.ToolbarItems.Count > 0 && page.Parent is NavigationPage navigationPage && navigationPage.Parent is FlyoutPage)
    {
        page.On<iOS>().SetUseSafeArea(true);
    }
});

This shorter version also works:

NavigationRenderer.Mapper.PrependToMapping(nameof(NavigationBar.CurrentPage), (h, n) =>
{
    if (n.Parent is FlyoutPage)
    {
        n.CurrentPage.On<iOS>().SetUseSafeArea(true);
    }
});

So I'd think a real code fix would just involve SetUseSafeArea getting called somewhere.