Skip to content
This repository was archived by the owner on May 1, 2024. It is now read-only.

iOS13 Fix Modal lifecycle #7923

Merged
merged 7 commits into from
Mar 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using System;
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;

namespace Xamarin.Forms.Controls.Issues
{
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 7878, "Page not popped on iOS 13 FormSheet swipe down", PlatformAffected.iOS)]
public class Issue7878 : TestContentPage
{
protected override void Init()
{
var label = new Label
{
Text = "Both modals should behave the same. With the FormSheet when swiping down the modal should be dismissed properly. And for both modals the Appearing event on this page should be called. If so, this tests succeeded."
};

var modalButtonFormSheet = new Button
{
Text = "Show Modal FormSheet"
};

modalButtonFormSheet.Clicked += Button_Clicked_FormSheet;

var modalButton = new Button
{
Text = "Show Modal Full Screen"
};

modalButton.Clicked += Button_Clicked;

var stackLayout = new StackLayout
{
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center,
Children = {
modalButton, modalButtonFormSheet
}
};

Content = stackLayout;
}

protected override void OnAppearing()
{
base.OnAppearing();

DisplayAlert("I have appeared!", "👋", "OK");
}

void Button_Clicked(object sender, EventArgs e)
{
Navigation.PushModalAsync(new ModalPage(false));
}

void Button_Clicked_FormSheet(object sender, EventArgs e)
{
Navigation.PushModalAsync(new ModalPage(true));
}

class ModalPage : ContentPage
{
public ModalPage(bool isFormSheet)
{
if (isFormSheet)
On<iOS>().SetModalPresentationStyle(UIModalPresentationStyle.FormSheet);

var button = new Button
{
Text = "Pressing this raises the popped event, swiping down as well!",
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center
};

button.Clicked += (o, a) =>
{
Navigation.PopModalAsync();
};

Content = button;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1233,6 +1233,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Issue7283.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue1658.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue5395.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue7878.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue6663.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue8004.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue7886.xaml.cs">
Expand Down Expand Up @@ -1726,33 +1727,35 @@
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7593.xaml">
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7789.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7792.xaml">
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7865.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7758.xaml">
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7593.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7789.xaml">
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7792.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7817.xaml">
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7758.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7865.xaml">
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7817.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
public enum UIModalPresentationStyle
{
FullScreen,
FormSheet
FormSheet,
Automatic
}
}
4 changes: 4 additions & 0 deletions Xamarin.Forms.Platform.iOS/Extensions/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ internal static UIModalPresentationStyle ToNativeModalPresentationStyle(this Pla
return UIModalPresentationStyle.FormSheet;
case PlatformConfiguration.iOSSpecific.UIModalPresentationStyle.FullScreen:
return UIModalPresentationStyle.FullScreen;
#if __XCODE11__
case PlatformConfiguration.iOSSpecific.UIModalPresentationStyle.Automatic:
return UIModalPresentationStyle.Automatic;
#endif
default:
throw new ArgumentOutOfRangeException(nameof(style));
}
Expand Down
30 changes: 26 additions & 4 deletions Xamarin.Forms.Platform.iOS/ModalWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
using System.Linq;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
using UIKit;
using Foundation;
using System.Threading.Tasks;

namespace Xamarin.Forms.Platform.iOS
{
internal class ModalWrapper : UIViewController
internal class ModalWrapper : UIViewController, IUIAdaptivePresentationControllerDelegate
{
IVisualElementRenderer _modal;

Expand All @@ -14,17 +16,37 @@ internal ModalWrapper(IVisualElementRenderer modal)
_modal = modal;

var elementConfiguration = modal.Element as IElementConfiguration<Page>;
var modalPresentationStyle = elementConfiguration?.On<PlatformConfiguration.iOS>()?.ModalPresentationStyle() ?? PlatformConfiguration.iOSSpecific.UIModalPresentationStyle.FullScreen;
ModalPresentationStyle = modalPresentationStyle.ToNativeModalPresentationStyle();
if (elementConfiguration?.On<PlatformConfiguration.iOS>()?.ModalPresentationStyle() is PlatformConfiguration.iOSSpecific.UIModalPresentationStyle style)
{
var result = style.ToNativeModalPresentationStyle();
#if __XCODE11__
if (!Forms.IsiOS13OrNewer && result == UIKit.UIModalPresentationStyle.Automatic)
{
result = UIKit.UIModalPresentationStyle.FullScreen;
}
#endif

ModalPresentationStyle = result;
}

View.BackgroundColor = UIColor.White;
View.AddSubview(modal.ViewController.View);
TransitioningDelegate = modal.ViewController.TransitioningDelegate;
AddChildViewController(modal.ViewController);

modal.ViewController.DidMoveToParentViewController(this);
#if __XCODE11__
if (Forms.IsiOS13OrNewer)
PresentationController.Delegate = this;
#endif
}

#if __XCODE11__
[Export("presentationControllerDidDismiss:")]
public async void DidDismiss(UIPresentationController presentationController)
{
await Application.Current.NavigationProxy.PopModalAsync(false);
}
#endif
public override void DismissViewController(bool animated, Action completionHandler)
{
if (PresentedViewController == null)
Expand Down
13 changes: 13 additions & 0 deletions Xamarin.Forms.Platform.iOS/PageExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using UIKit;
using System.Linq;

namespace Xamarin.Forms
{
Expand Down Expand Up @@ -39,5 +40,17 @@ public static UIViewController CreateViewController(this ContentPage page)
{
return Xamarin.Forms.PageExtensions.CreateViewController(page);
}

internal static Page GetCurrentPage(this Page currentPage)
{
if (currentPage.NavigationProxy.ModalStack.LastOrDefault() is Page modal)
return modal;
else if (currentPage is MasterDetailPage mdp)
return GetCurrentPage(mdp.Detail);
else if (currentPage is IPageContainer<Page> pc)
return GetCurrentPage(pc.CurrentPage);
else
return currentPage;
}
}
}
39 changes: 39 additions & 0 deletions Xamarin.Forms.Platform.iOS/Platform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using UIKit;
using Xamarin.Forms.Internals;
using RectangleF = CoreGraphics.CGRect;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;

namespace Xamarin.Forms.Platform.iOS
{
Expand Down Expand Up @@ -126,6 +127,9 @@ async Task<Page> INavigation.PopModalAsync(bool animated)

modal.DisposeModalAndChildRenderers();

if (!IsModalPresentedFullScreen(modal))
Page.GetCurrentPage()?.SendAppearing();

return modal;
}

Expand Down Expand Up @@ -158,6 +162,34 @@ Task INavigation.PushModalAsync(Page modal, bool animated)
{
EndEditing();


var elementConfiguration = modal as IElementConfiguration<Page>;

var presentationStyle = elementConfiguration?.On<PlatformConfiguration.iOS>()?.ModalPresentationStyle().ToNativeModalPresentationStyle();

bool shouldFire = true;

if (Forms.IsiOS13OrNewer)
{
if (presentationStyle == UIKit.UIModalPresentationStyle.FullScreen)
shouldFire = false; // This is mainly for backwards compatibility
}
else
{
// While the above IsiOS13OrNewer will always be false if __XCODE11__ is true
// the UIModalPresentationStyle.Automatic is the only Xcode 11 API
// for readability I decided to only take this part out
#if __XCODE11__
if (presentationStyle == UIKit.UIModalPresentationStyle.Automatic)
shouldFire = false;
#endif
if (presentationStyle == UIKit.UIModalPresentationStyle.FullScreen)
shouldFire = false; // This is mainly for backwards compatibility
}

if (_appeared && shouldFire)
Page.GetCurrentPage()?.SendDisappearing();

_modals.Add(modal);

#pragma warning disable CS0618 // Type or member is obsolete
Expand Down Expand Up @@ -614,6 +646,13 @@ internal void SubscribeToAlertsAndActionSheets()
});
}

static bool IsModalPresentedFullScreen(Page modal)
{
var elementConfiguration = modal as IElementConfiguration<Page>;
var presentationStyle = elementConfiguration?.On<PlatformConfiguration.iOS>()?.ModalPresentationStyle();
return presentationStyle != null && presentationStyle == PlatformConfiguration.iOSSpecific.UIModalPresentationStyle.FullScreen;
}

internal void UnsubscribeFromAlertsAndActionsSheets()
{
MessagingCenter.Unsubscribe<Page, ActionSheetArguments>(this, Page.ActionSheetSignalName);
Expand Down