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

Commit fd77991

Browse files
jfversluisPureWeen
andauthored
iOS13 Fix Modal lifecycle (#7923)
* Repro + fix * Cleanup * - logging * - merge fixes related to lifecycle on transparent pr * Update Issue7878.cs * Add Xcode11 directives * Update Platform.cs Co-authored-by: ShaneN <[email protected]> Co-authored-by: Shane Neuville <[email protected]>
1 parent 93cbdf2 commit fd77991

File tree

7 files changed

+181
-13
lines changed

7 files changed

+181
-13
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
using System;
2+
using Xamarin.Forms.CustomAttributes;
3+
using Xamarin.Forms.Internals;
4+
using Xamarin.Forms.PlatformConfiguration;
5+
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
6+
7+
namespace Xamarin.Forms.Controls.Issues
8+
{
9+
[Preserve(AllMembers = true)]
10+
[Issue(IssueTracker.Github, 7878, "Page not popped on iOS 13 FormSheet swipe down", PlatformAffected.iOS)]
11+
public class Issue7878 : TestContentPage
12+
{
13+
protected override void Init()
14+
{
15+
var label = new Label
16+
{
17+
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."
18+
};
19+
20+
var modalButtonFormSheet = new Button
21+
{
22+
Text = "Show Modal FormSheet"
23+
};
24+
25+
modalButtonFormSheet.Clicked += Button_Clicked_FormSheet;
26+
27+
var modalButton = new Button
28+
{
29+
Text = "Show Modal Full Screen"
30+
};
31+
32+
modalButton.Clicked += Button_Clicked;
33+
34+
var stackLayout = new StackLayout
35+
{
36+
HorizontalOptions = LayoutOptions.Center,
37+
VerticalOptions = LayoutOptions.Center,
38+
Children = {
39+
modalButton, modalButtonFormSheet
40+
}
41+
};
42+
43+
Content = stackLayout;
44+
}
45+
46+
protected override void OnAppearing()
47+
{
48+
base.OnAppearing();
49+
50+
DisplayAlert("I have appeared!", "👋", "OK");
51+
}
52+
53+
void Button_Clicked(object sender, EventArgs e)
54+
{
55+
Navigation.PushModalAsync(new ModalPage(false));
56+
}
57+
58+
void Button_Clicked_FormSheet(object sender, EventArgs e)
59+
{
60+
Navigation.PushModalAsync(new ModalPage(true));
61+
}
62+
63+
class ModalPage : ContentPage
64+
{
65+
public ModalPage(bool isFormSheet)
66+
{
67+
if (isFormSheet)
68+
On<iOS>().SetModalPresentationStyle(UIModalPresentationStyle.FormSheet);
69+
70+
var button = new Button
71+
{
72+
Text = "Pressing this raises the popped event, swiping down as well!",
73+
HorizontalOptions = LayoutOptions.Center,
74+
VerticalOptions = LayoutOptions.Center
75+
};
76+
77+
button.Clicked += (o, a) =>
78+
{
79+
Navigation.PopModalAsync();
80+
};
81+
82+
Content = button;
83+
}
84+
}
85+
}
86+
}

Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,6 +1236,7 @@
12361236
<Compile Include="$(MSBuildThisFileDirectory)Issue7283.cs" />
12371237
<Compile Include="$(MSBuildThisFileDirectory)Issue1658.cs" />
12381238
<Compile Include="$(MSBuildThisFileDirectory)Issue5395.cs" />
1239+
<Compile Include="$(MSBuildThisFileDirectory)Issue7878.cs" />
12391240
<Compile Include="$(MSBuildThisFileDirectory)Issue6663.cs" />
12401241
<Compile Include="$(MSBuildThisFileDirectory)Issue8004.cs" />
12411242
<Compile Include="$(MSBuildThisFileDirectory)Issue7886.xaml.cs">
@@ -1740,33 +1741,35 @@
17401741
</EmbeddedResource>
17411742
</ItemGroup>
17421743
<ItemGroup>
1743-
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7593.xaml">
1744+
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7789.xaml">
17441745
<SubType>Designer</SubType>
17451746
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
17461747
</EmbeddedResource>
17471748
</ItemGroup>
17481749
<ItemGroup>
1749-
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7792.xaml">
1750+
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7865.xaml">
17501751
<SubType>Designer</SubType>
17511752
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
17521753
</EmbeddedResource>
1753-
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7758.xaml">
1754+
</ItemGroup>
1755+
<ItemGroup>
1756+
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7593.xaml">
17541757
<SubType>Designer</SubType>
17551758
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
17561759
</EmbeddedResource>
17571760
</ItemGroup>
17581761
<ItemGroup>
1759-
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7789.xaml">
1762+
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7792.xaml">
17601763
<SubType>Designer</SubType>
17611764
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
17621765
</EmbeddedResource>
1763-
</ItemGroup>
1764-
<ItemGroup>
1765-
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7817.xaml">
1766+
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7758.xaml">
17661767
<SubType>Designer</SubType>
17671768
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
17681769
</EmbeddedResource>
1769-
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7865.xaml">
1770+
</ItemGroup>
1771+
<ItemGroup>
1772+
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7817.xaml">
17701773
<SubType>Designer</SubType>
17711774
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
17721775
</EmbeddedResource>

Xamarin.Forms.Core/PlatformConfiguration/iOSSpecific/UIModalPresentationStyle.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
public enum UIModalPresentationStyle
44
{
55
FullScreen,
6-
FormSheet
6+
FormSheet,
7+
Automatic
78
}
89
}

Xamarin.Forms.Platform.iOS/Extensions/Extensions.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ internal static UIModalPresentationStyle ToNativeModalPresentationStyle(this Pla
8484
return UIModalPresentationStyle.FormSheet;
8585
case PlatformConfiguration.iOSSpecific.UIModalPresentationStyle.FullScreen:
8686
return UIModalPresentationStyle.FullScreen;
87+
#if __XCODE11__
88+
case PlatformConfiguration.iOSSpecific.UIModalPresentationStyle.Automatic:
89+
return UIModalPresentationStyle.Automatic;
90+
#endif
8791
default:
8892
throw new ArgumentOutOfRangeException(nameof(style));
8993
}

Xamarin.Forms.Platform.iOS/ModalWrapper.cs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
using System.Linq;
33
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
44
using UIKit;
5+
using Foundation;
6+
using System.Threading.Tasks;
57

68
namespace Xamarin.Forms.Platform.iOS
79
{
8-
internal class ModalWrapper : UIViewController
10+
internal class ModalWrapper : UIViewController, IUIAdaptivePresentationControllerDelegate
911
{
1012
IVisualElementRenderer _modal;
1113

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

1618
var elementConfiguration = modal.Element as IElementConfiguration<Page>;
17-
var modalPresentationStyle = elementConfiguration?.On<PlatformConfiguration.iOS>()?.ModalPresentationStyle() ?? PlatformConfiguration.iOSSpecific.UIModalPresentationStyle.FullScreen;
18-
ModalPresentationStyle = modalPresentationStyle.ToNativeModalPresentationStyle();
19+
if (elementConfiguration?.On<PlatformConfiguration.iOS>()?.ModalPresentationStyle() is PlatformConfiguration.iOSSpecific.UIModalPresentationStyle style)
20+
{
21+
var result = style.ToNativeModalPresentationStyle();
22+
#if __XCODE11__
23+
if (!Forms.IsiOS13OrNewer && result == UIKit.UIModalPresentationStyle.Automatic)
24+
{
25+
result = UIKit.UIModalPresentationStyle.FullScreen;
26+
}
27+
#endif
28+
29+
ModalPresentationStyle = result;
30+
}
1931

2032
View.BackgroundColor = UIColor.White;
2133
View.AddSubview(modal.ViewController.View);
2234
TransitioningDelegate = modal.ViewController.TransitioningDelegate;
2335
AddChildViewController(modal.ViewController);
2436

2537
modal.ViewController.DidMoveToParentViewController(this);
38+
#if __XCODE11__
39+
if (Forms.IsiOS13OrNewer)
40+
PresentationController.Delegate = this;
41+
#endif
2642
}
27-
43+
#if __XCODE11__
44+
[Export("presentationControllerDidDismiss:")]
45+
public async void DidDismiss(UIPresentationController presentationController)
46+
{
47+
await Application.Current.NavigationProxy.PopModalAsync(false);
48+
}
49+
#endif
2850
public override void DismissViewController(bool animated, Action completionHandler)
2951
{
3052
if (PresentedViewController == null)

Xamarin.Forms.Platform.iOS/PageExtensions.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using UIKit;
3+
using System.Linq;
34

45
namespace Xamarin.Forms
56
{
@@ -39,5 +40,17 @@ public static UIViewController CreateViewController(this ContentPage page)
3940
{
4041
return Xamarin.Forms.PageExtensions.CreateViewController(page);
4142
}
43+
44+
internal static Page GetCurrentPage(this Page currentPage)
45+
{
46+
if (currentPage.NavigationProxy.ModalStack.LastOrDefault() is Page modal)
47+
return modal;
48+
else if (currentPage is MasterDetailPage mdp)
49+
return GetCurrentPage(mdp.Detail);
50+
else if (currentPage is IPageContainer<Page> pc)
51+
return GetCurrentPage(pc.CurrentPage);
52+
else
53+
return currentPage;
54+
}
4255
}
4356
}

Xamarin.Forms.Platform.iOS/Platform.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using UIKit;
99
using Xamarin.Forms.Internals;
1010
using RectangleF = CoreGraphics.CGRect;
11+
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
1112

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

127128
modal.DisposeModalAndChildRenderers();
128129

130+
if (!IsModalPresentedFullScreen(modal))
131+
Page.GetCurrentPage()?.SendAppearing();
132+
129133
return modal;
130134
}
131135

@@ -158,6 +162,34 @@ Task INavigation.PushModalAsync(Page modal, bool animated)
158162
{
159163
EndEditing();
160164

165+
166+
var elementConfiguration = modal as IElementConfiguration<Page>;
167+
168+
var presentationStyle = elementConfiguration?.On<PlatformConfiguration.iOS>()?.ModalPresentationStyle().ToNativeModalPresentationStyle();
169+
170+
bool shouldFire = true;
171+
172+
if (Forms.IsiOS13OrNewer)
173+
{
174+
if (presentationStyle == UIKit.UIModalPresentationStyle.FullScreen)
175+
shouldFire = false; // This is mainly for backwards compatibility
176+
}
177+
else
178+
{
179+
// While the above IsiOS13OrNewer will always be false if __XCODE11__ is true
180+
// the UIModalPresentationStyle.Automatic is the only Xcode 11 API
181+
// for readability I decided to only take this part out
182+
#if __XCODE11__
183+
if (presentationStyle == UIKit.UIModalPresentationStyle.Automatic)
184+
shouldFire = false;
185+
#endif
186+
if (presentationStyle == UIKit.UIModalPresentationStyle.FullScreen)
187+
shouldFire = false; // This is mainly for backwards compatibility
188+
}
189+
190+
if (_appeared && shouldFire)
191+
Page.GetCurrentPage()?.SendDisappearing();
192+
161193
_modals.Add(modal);
162194

163195
#pragma warning disable CS0618 // Type or member is obsolete
@@ -614,6 +646,13 @@ internal void SubscribeToAlertsAndActionSheets()
614646
});
615647
}
616648

649+
static bool IsModalPresentedFullScreen(Page modal)
650+
{
651+
var elementConfiguration = modal as IElementConfiguration<Page>;
652+
var presentationStyle = elementConfiguration?.On<PlatformConfiguration.iOS>()?.ModalPresentationStyle();
653+
return presentationStyle != null && presentationStyle == PlatformConfiguration.iOSSpecific.UIModalPresentationStyle.FullScreen;
654+
}
655+
617656
internal void UnsubscribeFromAlertsAndActionsSheets()
618657
{
619658
MessagingCenter.Unsubscribe<Page, ActionSheetArguments>(this, Page.ActionSheetSignalName);

0 commit comments

Comments
 (0)