Open btschumy opened 4 years ago
@btschumy Hi Bill, I have been having the same problem as you. Here's my work-around. I created an extension that walks up the UIViewController hierarchy and sets the ModalInPresentation property for every UIViewController. I call this extension from the ViewDidAppear method of a custom NavigationRenderer.
NOTE: It's possible that you can call this from other places in the ViewController lifecycle, but I have not tested that and I found that the ViewController didn't get wrapped in a ModalWrapper until pretty late in the lifecycle.
public static class UIViewController_Extensions
{
public static void SetModalInPresentation(this UIViewController viewController, bool modalInPresentation)
{
viewController.ModalInPresentation = modalInPresentation;
if (viewController.ParentViewController != null)
{
viewController.ParentViewController.SetModalInPresentation(modalInPresentation);
}
}
}
I was able to find a work-around because of your observation that the ModalInPresentation property worked on Xamarin.iOS but not on Xamarin.Forms. It seems like the issue is that modal ViewControllers are wrapped in a class called ModalWrapper and it's possible that ModalInPresentation is not being bubbled up through the ViewControllers. I read that you can set ModalInPresentation on any modal page in a navigation stack for the modal behavior to be updated, and it's possible that there is a disconnect where the navigation stack is not structured how the iOS system is expecting.
Thanks for sharing your observations and I hope this helps!
Hello from 2023!
I came across this problem in .NET MAUI. I've created a Frakenstien's monster of a fix using a suggestion here: https://github.com/dotnet/maui/issues/7174
In the iOS folder, I created the following class:
using Microsoft.Maui.Handlers;
using Microsoft.Maui.Platform;
using ContentView = Microsoft.Maui.Platform.ContentView;
namespace Corkboard.Mobile;
// https://github.com/dotnet/maui/issues/7174
public partial class AuthenticationPageHandler : PageHandler
{
protected override ContentView CreatePlatformView()
{
_ = VirtualView ??
throw new InvalidOperationException($"{nameof(VirtualView)} must be set to create a LayoutView");
_ = MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} cannot be null");
if (ViewController == null)
ViewController = new AuthenticationPageHandlerViewController(VirtualView, MauiContext);
if (ViewController is PageViewController pc && pc.CurrentPlatformView is ContentView pv)
return pv;
if (ViewController.View is Microsoft.Maui.Platform.ContentView cv)
return cv;
throw new InvalidOperationException(
$"PageViewController.View must be a {nameof(Microsoft.Maui.Platform.ContentView)}");
}
}
Also in the iOS folder, added the following class (thanks to @jeffington above for the extension method):
using Microsoft.Maui.Platform;
using UIKit;
namespace Corkboard.Mobile;
public class AuthenticationPageHandlerViewController : PageViewController
{
public AuthenticationPageHandlerViewController(IView page, IMauiContext mauiContext) : base(page, mauiContext)
{
}
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
this.SetModalInPresentation(true);
}
}
public static class UIViewControllerExtensions
{
public static void SetModalInPresentation(this UIViewController viewController, bool modalInPresentation)
{
// TODO Do I care if it's less than iOS 13?
viewController.ModalInPresentation = modalInPresentation;
if (viewController.ParentViewController != null)
{
viewController.ParentViewController.SetModalInPresentation(modalInPresentation);
}
}
}
And in my MauiProgram.cs:
builder.ConfigureMauiHandlers(collection =>
{
#if IOS
collection.AddHandler(typeof(AuthenticationPage), typeof(AuthenticationPageHandler));
#endif
});
I feel quite dirty. I'm not sure if there's a better way, but it does work.
Description
Setting the ModalInPresentation flag for a UIViewController should, according to Apple:
The default value of this property is NO. When you set it to YES, UIKit ignores events outside the view controller's bounds and prevents the interactive dismissal of the view controller while it is onscreen.
However, this flag does not seem to work in Xamarin Forms (all versions I've tried). If you set it YES, you can still dismiss the modal page by dragging it to the bottom of the screen. If the flag is set NO, you should be able to dismiss the page by tapping outside the pages boundary but this seems to fail as well.
I've created an example app at www.otherwise.com/ModalPresentation.zip that illustrates the problems. The example app uses a custom PageRenderer to set the ModalInPresentation flag in multiple places (since it wasn't really clear where it needs to be set).
Note, I've been told that this flag is working correctly in a native Xamarin iOS app. It seems to only fail in Xamarin Forms.
Note that this bug may be related to another problem I've reported in issue #12300. This refers to a crash when tapping outside the modal page and then dismissing the page.
Steps to Reproduce
Expected Behavior
The panel should not be able to be dismissed by dragging down with this flag set to true.
Actual Behavior
It can be dismissed by dragging.
Basic Information
Screenshots
Reproduction Link
www.otherwise.com/ModalPresentation.zip
Workaround
None that I've found