Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Popup size on Android and iOS #1361

Merged
merged 32 commits into from
Sep 29, 2023
Merged

Conversation

cat0363
Copy link
Contributor

@cat0363 cat0363 commented Aug 22, 2023

This PR corrects the Popup size to be calculated correctly when the Popup size is not explicitly specified.

Description of Change

The process for getting the window size has been made into a method.

[src\CommunityToolkit.Maui.Core\Views\Popup\PopupExtensions.android.cs]

static Size GetWindowSize(IWindowManager? windowManager, ViewGroup decorView)
{
    ArgumentNullException.ThrowIfNull(windowManager);

    int windowWidth;
    int windowHeight;
    int statusBarHeight;
    int navigationBarHeight;

    if (OperatingSystem.IsAndroidVersionAtLeast((int)BuildVersionCodes.R))
    {
        var windowMetrics = windowManager.CurrentWindowMetrics;
        var windowInsets = windowMetrics.WindowInsets.GetInsetsIgnoringVisibility(WindowInsets.Type.SystemBars());
        windowWidth = windowMetrics.Bounds.Width();
        windowHeight = windowMetrics.Bounds.Height();
        statusBarHeight = windowInsets.Top;
        navigationBarHeight = windowHeight < windowWidth ? windowInsets.Left + windowInsets.Right : windowInsets.Bottom;
    }
    else if (windowManager.DefaultDisplay is null)
    {
        throw new InvalidOperationException($"{nameof(IWindowManager)}.{nameof(IWindowManager.DefaultDisplay)} cannot be null");
    }
    else
    {
        APoint realSize = new();
        APoint displaySize = new();
        ARect contentRect = new();

        windowManager.DefaultDisplay.GetRealSize(realSize);
        windowManager.DefaultDisplay.GetSize(displaySize);
        decorView.GetWindowVisibleDisplayFrame(contentRect);

        windowWidth = realSize.X;
        windowHeight = realSize.Y;
        statusBarHeight = contentRect.Top;

        navigationBarHeight = realSize.Y < realSize.X
                                            ? (realSize.X - displaySize.X)
                                            : (realSize.Y - displaySize.Y);
    }

    windowWidth = (windowWidth - (windowHeight < windowWidth ? navigationBarHeight : 0));
    windowHeight = (windowHeight - ((windowHeight < windowWidth ? 0 : navigationBarHeight) + statusBarHeight));

    return new Size(windowWidth, windowHeight);
}

Then I modified the CalculateSizes method as follows:

[src\CommunityToolkit.Maui.Core\Views\Popup\PopupExtensions.android.cs]

static void CalculateSizes(IPopup popup, Context context, Size windowSize, ref int realWidth, ref int realHeight, ref int realContentWidth, ref int realContentHeight)
{
    ArgumentNullException.ThrowIfNull(popup.Content);

    var density = context.Resources?.DisplayMetrics?.Density ?? throw new InvalidOperationException($"Unable to determine density. {nameof(context.Resources.DisplayMetrics)} cannot be null");

    if (!popup.Size.IsZero)
    {
        realWidth = (int)context.ToPixels(popup.Size.Width);
        realHeight = (int)context.ToPixels(popup.Size.Height);
    }
    if (double.IsNaN(popup.Content.Width) || double.IsNaN(popup.Content.Height))
    {
        var size = popup.Content.Measure(windowSize.Width / density, windowSize.Height / density);
        realContentWidth = (int)context.ToPixels(size.Width);
        realContentHeight = (int)context.ToPixels(size.Height);
    }
    else
    {
        realContentWidth = (int)context.ToPixels(popup.Content.Width);
        realContentHeight = (int)context.ToPixels(popup.Content.Height);
    }

    realWidth = realWidth is 0 ? realContentWidth : realWidth;
    realHeight = realHeight is 0 ? realContentHeight : realHeight;

    if (realHeight is 0 || realWidth is 0)
    {
        realWidth = (int)(context.Resources?.DisplayMetrics?.WidthPixels * 0.8 ?? throw new InvalidOperationException($"Unable to determine width. {nameof(context.Resources.DisplayMetrics)} cannot be null"));
        realHeight = (int)(context.Resources?.DisplayMetrics?.HeightPixels * 0.6 ?? throw new InvalidOperationException($"Unable to determine height. {nameof(context.Resources.DisplayMetrics)} cannot be null"));
    }

    popup.Content.Measure(realWidth / density, realHeight / density);
}

Changed to recalculate the size within the size of the Window when the Popup's Content size is not specified.
And, Changed to limit Popup size to Window size in SetSize method.

[src\CommunityToolkit.Maui.Core\Views\Popup\PopupExtensions.android.cs]

realWidth = realWidth <= windowSize.Width ? realWidth : (int)windowSize.Width;
realHeight = realHeight <= windowSize.Height ? realHeight : (int)windowSize.Height;
window.SetLayout(realWidth, realHeight);

var childLayoutParams = (FrameLayout.LayoutParams)(child.LayoutParameters ?? throw new InvalidOperationException($"{nameof(child.LayoutParameters)} cannot be null"));
childLayoutParams.Width = realWidth;
childLayoutParams.Height = realHeight;
child.LayoutParameters = childLayoutParams;

horizontalParams = realWidth;
verticalParams = realHeight;

var containerLayoutParams = new FrameLayout.LayoutParams(horizontalParams, verticalParams);

With these changes, the Popup's size is now correctly calculated when no explicit size is specified for the Popup.

Linked Issues

PR Checklist

Additional information

Below are the verification results for Issue #1353.

You can see that the label placed inside the Popup wraps as intended.

Even if you specify an explicit size for the Popups Size when the Popups content is only a Label, the label
text was not wrapped before the fix, but after the fix, the label text is wrapped.

I layout the Popup as shown below and verified it.

<toolkit:Popup xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
    x:Class="MauiComm_IssuePopupWindows.PopupPage1" Size="100,100">

    <Label Text="1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ" TextColor="Black" />

</toolkit:Popup>

Below are the verification results.

[When VerticalOptions is Start]
I changed the HorizontalOptions to:

[Start] [Center] [End] [Fill]

[When VerticalOptions is Center]
I changed the HorizontalOptions to:

[Start] [Center] [End] [Fill]

[When VerticalOptions is End]
I changed the HorizontalOptions to:

[Start] [Center] [End] [Fill]

[When VerticalOptions is Fill]
I changed the HorizontalOptions to:

[Start] [Center] [End] [Fill]

Even if you explicitly specify the size of the Popup, you can see that the label inside the Popup is wrapped.

@pictos
Copy link
Member

pictos commented Aug 22, 2023

When not specifying the size, does Popup respects the LayoutOptions (Center, Fill, Start, End)?

@cat0363
Copy link
Contributor Author

cat0363 commented Aug 23, 2023

When not specifying the size, does Popup respects the LayoutOptions (Center, Fill, Start, End)?

@pictos , I'll fix it again because the PR I created doesn't respect the LayoutOptions when the Popup size is unspecified.
Thanks for the good question.

@cat0363 cat0363 mentioned this pull request Aug 23, 2023
6 tasks
@cat0363
Copy link
Contributor Author

cat0363 commented Aug 23, 2023

@pictos , Since iOS has a similar issue, is it okay to include the fix in this PR?
If there is no problem with including it, I will change the title later.
For Windows, I will include the fix in PR #1350. This is because the modifications conflict.

@cat0363 cat0363 changed the title Fix Popup size on Android Fix Popup size on Android and iOS Aug 23, 2023
@cat0363
Copy link
Contributor Author

cat0363 commented Aug 23, 2023

I made the following changes so that the LayoutOptions are respected when the Popup size is unspecified.

The below are changes on the Android side.

[src\CommunityToolkit.Maui.Core\Views\Popup\PopupExtensions.android.cs]

static void CalculateSizes(IPopup popup, Context context, Size windowSize, ref int realWidth, ref int realHeight, ref int realContentWidth, ref int realContentHeight)
{
    ArgumentNullException.ThrowIfNull(popup.Content);

    var density = context.Resources?.DisplayMetrics?.Density ?? throw new InvalidOperationException($"Unable to determine density. {nameof(context.Resources.DisplayMetrics)} cannot be null");

    if (!popup.Size.IsZero)
    {
        realWidth = (int)context.ToPixels(popup.Size.Width);
        realHeight = (int)context.ToPixels(popup.Size.Height);
    }
    else
    {
        if (double.IsNaN(popup.Content.Width) || double.IsNaN(popup.Content.Height))
        {
            var size = popup.Content.Measure(windowSize.Width / density, windowSize.Height / density);
            realContentWidth = (int)context.ToPixels(size.Width);
            realContentHeight = (int)context.ToPixels(size.Height);

            if (double.IsNaN(popup.Content.Width))
            {
                realContentWidth = popup.HorizontalOptions == LayoutAlignment.Fill ? (int)windowSize.Width : realContentWidth;
            }
            if (double.IsNaN(popup.Content.Height))
            {
                realContentHeight = popup.VerticalOptions == LayoutAlignment.Fill ? (int)windowSize.Height : realContentHeight;
            }
        }
        else
        {
            realContentWidth = (int)context.ToPixels(popup.Content.Width);
            realContentHeight = (int)context.ToPixels(popup.Content.Height);
        }
    }

    realWidth = Math.Min(realWidth is 0 ? realContentWidth : realWidth, (int)windowSize.Width);
    realHeight = Math.Min(realHeight is 0 ? realContentHeight : realHeight, (int)windowSize.Height);

    if (realHeight is 0 || realWidth is 0)
    {
        realWidth = (int)(context.Resources?.DisplayMetrics?.WidthPixels * 0.8 ?? throw new InvalidOperationException($"Unable to determine width. {nameof(context.Resources.DisplayMetrics)} cannot be null"));
        realHeight = (int)(context.Resources?.DisplayMetrics?.HeightPixels * 0.6 ?? throw new InvalidOperationException($"Unable to determine height. {nameof(context.Resources.DisplayMetrics)} cannot be null"));
    }

    popup.Content.Measure(realWidth / density, realHeight / density);
}

Since I moved the code from the SetSize method to the CalculateSizes method, I removed the two lines
below from the SetSize method.

realWidth = realWidth <= windowSize.Width ? realWidth : (int)windowSize.Width;
realHeight = realHeight <= windowSize.Height ? realHeight : (int)windowSize.Height;

The below are changes on the iOS side.

[src\CommunityToolkit.Maui.Core\Views\Popup\PopupExtensions.macios.cs]

public static void SetSize(this MauiPopup mauiPopup, in IPopup popup)
{
    ArgumentNullException.ThrowIfNull(popup.Content);

    CGRect frame;

    if (mauiPopup.ViewController?.View?.Window is UIWindow window)
    {
        frame = window.Frame;
    }
    else
    {
        frame = UIScreen.MainScreen.Bounds;
    }

    CGSize currentSize;

    if (!popup.Size.IsZero)
    {
        currentSize = new CGSize(popup.Size.Width, popup.Size.Height);
    }
    else
    {
        if (double.IsNaN(popup.Content.Width) || double.IsNaN(popup.Content.Height))
        {
            var content = popup.Content.ToPlatform(popup.Handler?.MauiContext ?? throw new InvalidOperationException($"{nameof(popup.Handler.MauiContext)} Cannot Be Null"));
            var contentSize = content.SizeThatFits(new CGSize(frame.Width, frame.Height));
            var width = contentSize.Width;
            var height = contentSize.Height;

            if (double.IsNaN(popup.Content.Width))
            {
                width = popup.HorizontalOptions == Microsoft.Maui.Primitives.LayoutAlignment.Fill ? frame.Size.Width : width;
            }
            if (double.IsNaN(popup.Content.Height))
            {
                height = popup.VerticalOptions == Microsoft.Maui.Primitives.LayoutAlignment.Fill ? frame.Size.Height : height;
            }

            currentSize = new CGSize(width, height);
        }
        else
        {
            currentSize = new CGSize(popup.Content.Width, popup.Content.Height);
        }
    }

    currentSize.Width = NMath.Min(currentSize.Width, frame.Size.Width);
    currentSize.Height = NMath.Min(currentSize.Height, frame.Size.Height);
    mauiPopup.PreferredContentSize = currentSize;
}

Changed code to respect LayoutOptions when popup size is unspecified and popup content size is
unspecified on both Android and iOS.

Verified whether LayoutOptions are respected when Popup size is not specified.
The layout of the Popup used for verification is as follows.

<toolkit:Popup xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
    x:Class="MauiComm_IssuePopupWindows.PopupPage1">

    <Label Text="1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ" TextColor="Black" HorizontalOptions="Start" />

</toolkit:Popup>

Below are the verification results on Android.

[When VerticalOptions is Start]
I changed the HorizontalOptions to:

[Start] [Center] [End] [Fill]

[When VerticalOptions is Center]
I changed the HorizontalOptions to:

[Start] [Center] [End] [Fill]

[When VerticalOptions is End]
I changed the HorizontalOptions to:

[Start] [Center] [End] [Fill]

[When VerticalOptions is Fill]
I changed the HorizontalOptions to:

[Start] [Center] [End] [Fill]

Below are the verification results on iOS.

[When VerticalOptions is Start]
I changed the HorizontalOptions to:

[Start] [Center] [End] [Fill]

[When VerticalOptions is Center]
I changed the HorizontalOptions to:

[Start] [Center] [End] [Fill]

[When VerticalOptions is End]
I changed the HorizontalOptions to:

[Start] [Center] [End] [Fill]

[When VerticalOptions is Fill]
I changed the HorizontalOptions to:

[Start] [Center] [End] [Fill]

For both Android and iOS, you can see that LayoutOptions are respected when the Popup size
is unspecified and the Popup Content size is unspecified.

And, I laid out the Popup like this:

<toolkit:Popup xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
    x:Class="MauiComm_VerifyPopupStyle.Popup6" VerticalOptions="Center" HorizontalOptions="Start">

    <VerticalStackLayout>
        <Label Text="Popup" FontSize="20"/>
        <BoxView HeightRequest="3" Color="AliceBlue" />        
        <Label x:Name="txt1" Text="Short String" />
        <Label x:Name="txt2" Text="Long String1 Long String2 Long String3 Long String4 Long String5 Long String6 Long String7 Long String8 Long String9 Long String10 Long String" />
    </VerticalStackLayout>

</toolkit:Popup>

Below is the execution result on iOS.

You can see that the labels are wrapped like in Android.

@cat0363
Copy link
Contributor Author

cat0363 commented Aug 23, 2023

Below are additional validation results.

<toolkit:Popup xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
    x:Class="MauiComm_IssuePopupWindows.PopupPage2">

    <Grid WidthRequest="100">
        <Grid WidthRequest="10" HeightRequest="10" VerticalOptions="Start" HorizontalOptions="Start" BackgroundColor="Blue" />
        <Grid WidthRequest="10" HeightRequest="10" VerticalOptions="Start" HorizontalOptions="End" BackgroundColor="Blue" />
        <Grid WidthRequest="10" HeightRequest="10" VerticalOptions="End" HorizontalOptions="Start" BackgroundColor="Blue" />
        <Grid WidthRequest="10" HeightRequest="10" VerticalOptions="End" HorizontalOptions="End" BackgroundColor="Blue" />
    </Grid>

</toolkit:Popup>

Below are the verification results on Android.

[When VerticalOptions is Start]
I changed the HorizontalOptions to:

[Start] [Center] [End] [Fill]

[When VerticalOptions is Center]
I changed the HorizontalOptions to:

[Start] [Center] [End] [Fill]

[When VerticalOptions is End]
I changed the HorizontalOptions to:

[Start] [Center] [End] [Fill]

[When VerticalOptions is Fill]
I changed the HorizontalOptions to:

[Start] [Center] [End] [Fill]

Below are the verification results on iOS.

[When VerticalOptions is Start]
I changed the HorizontalOptions to:

[Start] [Center] [End] [Fill]

[When VerticalOptions is Center]
I changed the HorizontalOptions to:

[Start] [Center] [End] [Fill]

[When VerticalOptions is End]
I changed the HorizontalOptions to:

[Start] [Center] [End] [Fill]

[When VerticalOptions is Fill]
I changed the HorizontalOptions to:

[Start] [Center] [End] [Fill]

You can see that the VerticalOptions are respected because the height is unspecified.
I won't post the test results, but it will now respect HorizontalOptions when width is unspecified.

@cat0363
Copy link
Contributor Author

cat0363 commented Aug 23, 2023

@pictos , Windows test results are posted below.
#1350 (comment)

@cat0363
Copy link
Contributor Author

cat0363 commented Aug 24, 2023

Following the comments below, I have made similar fixes to this PR as well.
#1350 (comment)

@cat0363
Copy link
Contributor Author

cat0363 commented Aug 31, 2023

@pictos , @VladislavAntonyuk
I want to fix the position when popups are overlaid on iOS.
If the first Popup's VerticalOptions and HorizontalOptions are not Start, the second Popup will be displayed
in an unintended position. Once the fix is ​​complete, I'll post it here.

@cat0363
Copy link
Contributor Author

cat0363 commented Aug 31, 2023

I'm sorry for the change after approval. Below are the corrections.

[src\CommunityToolkit.Maui.Core\Handlers\Popup\PopupHandler.macios.cs]

public static async void MapOnClosed(PopupHandler handler, IPopup view, object? result)
{
    var pc = handler.PlatformView.PresentationController;
    if (pc is not null)
    {
        if (pc.PresentedViewController is UIViewController pvc)
        {
            await pvc.DismissViewControllerAsync(true);
        }
    }

    view.HandlerCompleteTCS.TrySetResult();

    handler.DisconnectHandler(handler.PlatformView);
}

This fix is ​​taken from PR #1369.
The above is a modification to close the Popup in order from the last displayed Popup when displaying Popups overlaid.

[src\CommunityToolkit.Maui.Core\Views\Popup\PopupExtensions.macios.cs]

public static void SetLayout(this MauiPopup mauiPopup, in IPopup popup)
{
    if (mauiPopup.View is null)
    {
        return;
    }

    CGRect frame;

    if (mauiPopup.ViewController?.View?.Window is UIWindow window)
    {
        frame = window.Frame;
    }
    else
    {
        frame = UIScreen.MainScreen.Bounds;
    }

    if (mauiPopup.PopoverPresentationController is null)
    {
        throw new InvalidOperationException("PopoverPresentationController cannot be null");
    }

    if (popup.Anchor is null)
    {
        omit ...

        if (mauiPopup.ViewController?.PopoverPresentationController is UIPopoverPresentationController popoverPresentationController)
        {
            mauiPopup.PopoverPresentationController.SourceView = popoverPresentationController.SourceView;
        }
        mauiPopup.PopoverPresentationController.SourceRect = new CGRect(originX, originY, 0, 0);
        mauiPopup.PopoverPresentationController.PermittedArrowDirections = 0;
        // From the point of view of usability, the top, bottom, left, and right values of UIEdgeInsets cannot all be 0.
        // If you specify 0 for the top, bottom, left, and right of UIEdgeInsets, the default margins will be added, so 
        // specify a value as close to 0 here as possible.
        mauiPopup.PopoverPresentationController.PopoverLayoutMargins = new UIEdgeInsets(0.0001f, 0.0001f, 0.0001f, 0.0001f);
    }
    else
    {
        var view = popup.Anchor.ToPlatform(popup.Handler?.MauiContext ?? throw new InvalidOperationException($"{nameof(popup.Handler.MauiContext)} Cannot Be Null"));
        mauiPopup.PopoverPresentationController.SourceView = view;
        mauiPopup.PopoverPresentationController.SourceRect = view.Bounds;
    }
}

The above is a correction of the base position of the second and subsequent Popups.
The Popup's SourceView is set to the View that is the original display source of the Popup.

The verification results before and after modification are shown below.

The 1st Popup has HorizontalOptions="End" and VerticalOptions="End" set.
The 2nd Popup has HorizontalOptions="Center" and VerticalOptions="Center" set.
The 3rd Popup has HorizontalOptions="Start" and VerticalOptions="Start" set.

[Before Fix] [After Fix]
iPhone.14.iOS.16.4.2023-08-31.11-34-55.mp4
iPhone.14.iOS.16.4.2023-08-31.11-10-57.mp4

Before the modification, when the third Popup was closed, the second Popup was also closed, but after the modification, only the third Popup was closed.

Before the correction, the next Popup was displayed starting from the position of the previous Popup, but after the correction, the Popup is displayed starting from the View that is the display source of the Popup.

With the overlay fix in PR #1369, the second and subsequent Popups will no longer be transparent.

@cat0363
Copy link
Contributor Author

cat0363 commented Sep 24, 2023

@brminnick , Currently, the following warning is output and the iOS side does not function as before,
so I would like to target the fix for PR #1409 only to MacCatalyst.

[Presentation] Presenting view controller <CommunityToolkit_Maui_Core_Views_MauiPopup: 0x7f97cff7b010> from detached view controller <Microsoft_Maui_Platform_PageViewController: 0x7f97cffa0590> is discouraged.

I would like to include the fix for Issue #1416 in this PR. Below are the changes.

[src\CommunityToolkit.Maui.Core\Views\Popup\MauiPopup.macios.cs]

public void SetElement(IPopup element)
{
    if (element.Parent?.Handler is not PageHandler)
    {
        throw new InvalidOperationException($"The {nameof(element.Parent)} must be of type {typeof(PageHandler)}.");
    }

    VirtualView = element;
    ModalPresentationStyle = UIModalPresentationStyle.Popover;

    _ = View ?? throw new InvalidOperationException($"{nameof(View)} cannot be null.");
    _ = VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} cannot be null.");

#if MACCATALYST
    var pagehandler = VirtualView.Parent.Handler as PageHandler;
    var rootViewController = pagehandler?.ViewController ?? WindowStateManager.Default.GetCurrentUIViewController() ?? throw new InvalidOperationException($"{nameof(PageHandler.ViewController)} cannot be null.");
#else
    var rootViewController = WindowStateManager.Default.GetCurrentUIViewController() ?? throw new InvalidOperationException($"{nameof(PageHandler.ViewController)} cannot be null.");
#endif

    ViewController ??= rootViewController;
    SetDimmingBackgroundEffect();
}

If I can find a better solution, I would like to create a new PR then. Thank you.

Copy link
Collaborator

@brminnick brminnick left a comment

Choose a reason for hiding this comment

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

Thanks @cat0363! FYI - I added the sample you created in your reproduction to the official sample app. Great work!

This is really really close! I confirmed that everything works as expected on iOS + Android.

But on macOS, I'm seeing strange behavior in the CustomSizeAndPositionPopupPage:

  • When VerticalOptions == End, the Popup doesn't appear.
  • When HorizontalOptions == End, the Popup appears outside of the macOS window
    ScreenFlow

@VladislavAntonyuk
Copy link
Collaborator

Seems like the issue in calculating the offset. Popup is moved half of its size to the right

@cat0363
Copy link
Contributor Author

cat0363 commented Sep 26, 2023

@brminnick , Thank you for verifying with MacCatalyst.
When I verified the operation of PR #1409, I also noticed that the Popup position on MacCatalyst was incorrect.
By taking into account the height of the title bar and the height of the navigation bar, the vertical position will be
close to what you expect. Regarding the horizontal position, it works as expected considering the offset of 20,
but I don't see a clear reason for this 20. If you specify Start for HorizontalOptions, the position of the Popup will
strangely shift so that it does not cover the close button, so this may be due to that shift.

systemMinimumLayoutMargins may be related, but I'm not sure ...

@cat0363
Copy link
Contributor Author

cat0363 commented Sep 26, 2023

I will reconsider including the rounding process when the Popup size exceeds the screen size.

@cat0363
Copy link
Contributor Author

cat0363 commented Sep 26, 2023

It seems that MacCatalyst does not allow Popup to completely cover the caller's screen as it does on iOS.
I'm not sure if that's the MacCatalyst spec. Even if the horizontal position is 0, some margin is always provided.
This is why magic numbers exist.

@cat0363
Copy link
Contributor Author

cat0363 commented Sep 27, 2023

In the case of MacCatalyst, there is a margin that is always taken on the left side, so modify it to take that
margin around the Popup. It probably looks prettier that way.

@cat0363
Copy link
Contributor Author

cat0363 commented Sep 27, 2023

For MacCatalyst, I modified it so that a margin of 18 is taken around the Popup by default.
This 18 is the minimum margin on the left side of the Popup in MacCatalyst.

#if MACCATALYST
    static nfloat popupMargin = 18f;
#endif

You may need to look into the MacCatalyst specifications to find out why a minimum margin of 18 is required.
I haven't investigated that far.

@cat0363
Copy link
Contributor Author

cat0363 commented Sep 27, 2023

I have uploaded the fix for Issue #1423.
I fixed the size calculation when the Popup size is specified.

static void CalculateSizes(IPopup popup, Context context, Size windowSize, ref int realWidth, ref int realHeight, ref int realContentWidth, ref int realContentHeight)
{
    ArgumentNullException.ThrowIfNull(popup.Content);

    var density = context.Resources?.DisplayMetrics?.Density ?? throw new InvalidOperationException($"Unable to determine density. {nameof(context.Resources.DisplayMetrics)} cannot be null");

    if (popup.Size.IsZero)
    {
        if (double.IsNaN(popup.Content.Width) || double.IsNaN(popup.Content.Height))
        {
            var size = popup.Content.Measure(windowSize.Width / density, windowSize.Height / density);
            realContentWidth = (int)context.ToPixels(size.Width);
            realContentHeight = (int)context.ToPixels(size.Height);

            if (double.IsNaN(popup.Content.Width))
            {
                realContentWidth = popup.HorizontalOptions == LayoutAlignment.Fill ? (int)windowSize.Width : realContentWidth;
            }
            if (double.IsNaN(popup.Content.Height))
            {
                realContentHeight = popup.VerticalOptions == LayoutAlignment.Fill ? (int)windowSize.Height : realContentHeight;
            }
        }
        else
        {
            realContentWidth = (int)context.ToPixels(popup.Content.Width);
            realContentHeight = (int)context.ToPixels(popup.Content.Height);
        }
    }
    else
    {
        realWidth = (int)context.ToPixels(popup.Size.Width);
        realHeight = (int)context.ToPixels(popup.Size.Height);

        var size = popup.Content.Measure(popup.Size.Width, popup.Size.Height);
        realContentWidth = (int)context.ToPixels(size.Width);
        realContentHeight = (int)context.ToPixels(size.Height);							
    }

    realWidth = Math.Min(realWidth is 0 ? realContentWidth : realWidth, (int)windowSize.Width);
    realHeight = Math.Min(realHeight is 0 ? realContentHeight : realHeight, (int)windowSize.Height);

    if (realHeight is 0 || realWidth is 0)
    {
        realWidth = (int)(context.Resources?.DisplayMetrics?.WidthPixels * 0.8 ?? throw new InvalidOperationException($"Unable to determine width. {nameof(context.Resources.DisplayMetrics)} cannot be null"));
        realHeight = (int)(context.Resources?.DisplayMetrics?.HeightPixels * 0.6 ?? throw new InvalidOperationException($"Unable to determine height. {nameof(context.Resources.DisplayMetrics)} cannot be null"));
    }
}

Below is a video of the verification results.

Android.Emulator.-.pixel_2_-_api_30_5554.2023-09-27.17-02-54.mp4

Added squares to the four corners of Popup in the reproduction code of Issue #1423.

I tried rotating the screen and verifying it.

[Before Rotation] [After Rotation]

@cat0363
Copy link
Contributor Author

cat0363 commented Sep 29, 2023

Below is a verification video using MacCatalyst.

[Width = 100, Height = 100]

2023-09-29.17.11.02.mov

[Width = 1000, Height = 100]

2023-09-29.17.22.18.mov

[Width = 100, Height = 1000]

2023-09-29.17.23.41.mov

[Width = 1000, Height = 1000]

2023-09-29.17.20.19.mov

Copy link
Collaborator

@brminnick brminnick left a comment

Choose a reason for hiding this comment

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

Awesome!! Thank you so much Kenji for your always amazing work 💯

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants