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] OnSizeAllocated called repeatedly using On<iOS>() .SetUseSafeArea(true); #22090

Open czuck opened 2 weeks ago

czuck commented 2 weeks ago

Description

App appears hung and is non responsive. Debug line added to OnSizeAllocated is written hundreds of time, width is always the same, height switches between 896 and 814, app eventually crashes.

Debug.WriteLine("****** Width = " + width + " Height = " + height + " Counter = " + ++counter + "***********");

[0:] ** Width = 331 Height = 814 Counter = 1187* [0:] ** Width = 331 Height = 896 Counter = 1188* [0:] ** Width = 331 Height = 814 Counter = 1189* [0:] ** Width = 331 Height = 896 Counter = 1190* [0:] ** Width = 331 Height = 814 Counter = 1191* [0:] ** Width = 331 Height = 896 Counter = 1192* [0:] ** Width = 331 Height = 814 Counter = 1193***

Steps to Reproduce

Create a File > new maui App. Create a MainFlyoutPage : Flyout page with the code:

public class MainFlyoutPage : FlyoutPage
{
    public MainFlyoutPage()
    {
        Flyout = new MenuPage();
        Detail = New NavigationPage(new DetailPage());
    }
}

Detail page can be anything. Create a MenuPage with the code:

public partial class MenuPage : ContentPage
{
    public const double Tolerance = 0.000000001;
    private double _width = 0;
    private double _height = 0;
    private int counter = 0;

    public MenuPage()
    {
        InitializeComponent();

    }

    protected override void OnSizeAllocated(double width, double height)
    {
        base.OnSizeAllocated(width, height);
        Debug.WriteLine("****** Width = " + width + " Height = " + height + " Counter = " + ++counter + "***********");
        if ((Math.Abs(width - _width) > Tolerance || Math.Abs(height - _height) > Tolerance) &&
            width != 0)
        {
            _width = width;
            _height = height;
            RenderPage();
        }
    }

    public void RenderPage()
    {
        Content = null;
        On<Microsoft.Maui.Controls.PlatformConfiguration.iOS>().SetUseSafeArea(true);
        var background = new Image
        {
            Source = "dotnet_bot.png"
        };
        Content = background;
    }

Run the app and watch the output.

Link to public reproduction project repository

No response

Version with bug

8.0.21 SR4.1

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

No response

Did you find any workaround?

No response

Relevant log output

No response

jaosnz-rep commented 1 week ago

Can repro this issue at iOS platform on the latest 17.10 Preview 5 (8.0.21&8.0.14). image

wrexbe commented 1 week ago

Simpler reproduction

public class MenuPage : ContentPage
{
    private int _counter;

    public MenuPage()
    {
        Title = "Menu";
        On<Microsoft.Maui.Controls.PlatformConfiguration.iOS>().SetUseSafeArea(true);
    }

    protected override void OnSizeAllocated(double width, double height)
    {
        Debug.WriteLine($"****** Width = {width} Height = {height} Counter = {++_counter} ***********");
        Content = new Border { WidthRequest = 100, HeightRequest = 100 };
    }
}

I think it happens like this

  1. Setting SetUseSafeArea to true, registers something that is watching MenuPage for changes, and when it sees a change it tries to update the menu page using something called CrossPlatformArrange.
  2. The Flyout page is not using the same size the CrossPlatformArrange is trying to make the Menu Page.
  3. When the Content is set, Flyout rechecks the menu page, and notices the change, and tries to set it.
  4. The thing that is listening because of the SetUseSafeArea, notices, and tries to change it back again as well.
  5. They keep doing this forever, both trying to set it to different sizes, and the loop never ends.