Skip to content

Instantly share code, notes, and snippets.

@r0b0t3d
Last active July 6, 2022 05:58
Show Gist options
  • Save r0b0t3d/3c9f77434e6fbcfa78698dcf57614fad to your computer and use it in GitHub Desktop.
Save r0b0t3d/3c9f77434e6fbcfa78698dcf57614fad to your computer and use it in GitHub Desktop.
[ios] Trigger onRequestClose when swiping down a pageSheet
diff --git a/node_modules/react-native/React/Views/RCTModalHostView.h b/node_modules/react-native/React/Views/RCTModalHostView.h
index e16dd22..97f24a6 100644
--- a/node_modules/react-native/React/Views/RCTModalHostView.h
+++ b/node_modules/react-native/React/Views/RCTModalHostView.h
@@ -17,7 +17,7 @@
@protocol RCTModalHostViewInteractor;
-@interface RCTModalHostView : UIView <RCTInvalidating>
+@interface RCTModalHostView : UIView <RCTInvalidating, UIAdaptivePresentationControllerDelegate>
@property (nonatomic, copy) NSString *animationType;
@property (nonatomic, assign) UIModalPresentationStyle presentationStyle;
@@ -31,9 +31,9 @@
@property (nonatomic, copy) NSArray<NSString *> *supportedOrientations;
@property (nonatomic, copy) RCTDirectEventBlock onOrientationChange;
+@property (nonatomic, copy) RCTDirectEventBlock onRequestClose;
#if TARGET_OS_TV
-@property (nonatomic, copy) RCTDirectEventBlock onRequestClose;
@property (nonatomic, strong) RCTTVRemoteHandler *tvRemoteHandler;
#endif
diff --git a/node_modules/react-native/React/Views/RCTModalHostView.m b/node_modules/react-native/React/Views/RCTModalHostView.m
index 95d572b..7e4f4c4 100644
--- a/node_modules/react-native/React/Views/RCTModalHostView.m
+++ b/node_modules/react-native/React/Views/RCTModalHostView.m
@@ -43,6 +43,10 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge
if ((self = [super initWithFrame:CGRectZero])) {
_bridge = bridge;
_modalViewController = [RCTModalHostViewController new];
+ // Transparency breaks for overFullScreen in iOS < 13
+ if (@available(iOS 13.0, *)) {
+ _modalViewController.presentationController.delegate = self;
+ }
UIView *containerView = [UIView new];
containerView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
_modalViewController.view = containerView;
@@ -63,6 +67,24 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge
return self;
}
+// Method must be implemented, otherwise iOS defaults to 'automatic' (pageSheet on >= iOS 13.0)
+- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller traitCollection:(UITraitCollection *)traitCollection
+{
+ if (self.presentationStyle == UIModalPresentationFullScreen && self.isTransparent) {
+ return UIModalPresentationOverFullScreen;
+ }
+ return self.presentationStyle;
+}
+
+// Method must be implemented, otherwise iOS defaults to 'automatic' (pageSheet on >= iOS 13.0)
+- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller
+{
+ if (self.presentationStyle == UIModalPresentationFullScreen && self.isTransparent) {
+ return UIModalPresentationOverFullScreen;
+ }
+ return self.presentationStyle;
+}
+
#if TARGET_OS_TV
- (void)menuButtonPressed:(__unused UIGestureRecognizer *)gestureRecognizer
{
@@ -70,10 +92,12 @@ - (void)menuButtonPressed:(__unused UIGestureRecognizer *)gestureRecognizer
_onRequestClose(nil);
}
}
+#endif
- (void)setOnRequestClose:(RCTDirectEventBlock)onRequestClose
{
_onRequestClose = onRequestClose;
+ #if TARGET_OS_TV
if (_reactSubview) {
if (_onRequestClose && _menuButtonGestureRecognizer) {
[_reactSubview addGestureRecognizer:_menuButtonGestureRecognizer];
@@ -81,8 +105,8 @@ - (void)setOnRequestClose:(RCTDirectEventBlock)onRequestClose
[_reactSubview removeGestureRecognizer:_menuButtonGestureRecognizer];
}
}
+ #endif
}
-#endif
- (void)notifyForBoundsChange:(CGRect)newBounds
{
@@ -156,6 +180,13 @@ - (void)didUpdateReactSubviews
// Do nothing, as subview (singular) is managed by `insertReactSubview:atIndex:`
}
+- (void)presentationControllerDidDismiss:(UIPresentationController *)presentationController
+{
+ if (_onRequestClose) {
+ _onRequestClose(nil);
+ }
+}
+
- (void)dismissModalViewController
{
if (_isPresented) {
diff --git a/node_modules/react-native/React/Views/RCTModalHostViewManager.m b/node_modules/react-native/React/Views/RCTModalHostViewManager.m
index 44f9ac9..9c0d13c 100644
--- a/node_modules/react-native/React/Views/RCTModalHostViewManager.m
+++ b/node_modules/react-native/React/Views/RCTModalHostViewManager.m
@@ -108,9 +108,6 @@ - (void)invalidate
RCT_EXPORT_VIEW_PROPERTY(identifier, NSNumber)
RCT_EXPORT_VIEW_PROPERTY(supportedOrientations, NSArray)
RCT_EXPORT_VIEW_PROPERTY(onOrientationChange, RCTDirectEventBlock)
-
-#if TARGET_OS_TV
RCT_EXPORT_VIEW_PROPERTY(onRequestClose, RCTDirectEventBlock)
-#endif
@end
diff --git a/node_modules/react-native/React/Views/RCTModalHostView.h b/node_modules/react-native/React/Views/RCTModalHostView.h
index e16dd22..97f24a6 100644
--- a/node_modules/react-native/React/Views/RCTModalHostView.h
+++ b/node_modules/react-native/React/Views/RCTModalHostView.h
@@ -17,7 +17,7 @@
@protocol RCTModalHostViewInteractor;
-@interface RCTModalHostView : UIView <RCTInvalidating>
+@interface RCTModalHostView : UIView <RCTInvalidating, UIAdaptivePresentationControllerDelegate>
@property (nonatomic, copy) NSString *animationType;
@property (nonatomic, assign) UIModalPresentationStyle presentationStyle;
@@ -31,9 +31,9 @@
@property (nonatomic, copy) NSArray<NSString *> *supportedOrientations;
@property (nonatomic, copy) RCTDirectEventBlock onOrientationChange;
+@property (nonatomic, copy) RCTDirectEventBlock onRequestClose;
#if TARGET_OS_TV
-@property (nonatomic, copy) RCTDirectEventBlock onRequestClose;
@property (nonatomic, strong) RCTTVRemoteHandler *tvRemoteHandler;
#endif
diff --git a/node_modules/react-native/React/Views/RCTModalHostView.m b/node_modules/react-native/React/Views/RCTModalHostView.m
index 95d572b..7e4f4c4 100644
--- a/node_modules/react-native/React/Views/RCTModalHostView.m
+++ b/node_modules/react-native/React/Views/RCTModalHostView.m
@@ -43,6 +43,10 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge
if ((self = [super initWithFrame:CGRectZero])) {
_bridge = bridge;
_modalViewController = [RCTModalHostViewController new];
+ // Transparency breaks for overFullScreen in iOS < 13
+ if (@available(iOS 13.0, *)) {
+ _modalViewController.presentationController.delegate = self;
+ }
UIView *containerView = [UIView new];
containerView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
_modalViewController.view = containerView;
@@ -63,6 +67,24 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge
return self;
}
+// Method must be implemented, otherwise iOS defaults to 'automatic' (pageSheet on >= iOS 13.0)
+- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller traitCollection:(UITraitCollection *)traitCollection
+{
+ if (self.presentationStyle == UIModalPresentationFullScreen && self.isTransparent) {
+ return UIModalPresentationOverFullScreen;
+ }
+ return self.presentationStyle;
+}
+
+// Method must be implemented, otherwise iOS defaults to 'automatic' (pageSheet on >= iOS 13.0)
+- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller
+{
+ if (self.presentationStyle == UIModalPresentationFullScreen && self.isTransparent) {
+ return UIModalPresentationOverFullScreen;
+ }
+ return self.presentationStyle;
+}
+
#if TARGET_OS_TV
- (void)menuButtonPressed:(__unused UIGestureRecognizer *)gestureRecognizer
{
@@ -70,10 +92,12 @@ - (void)menuButtonPressed:(__unused UIGestureRecognizer *)gestureRecognizer
_onRequestClose(nil);
}
}
+#endif
- (void)setOnRequestClose:(RCTDirectEventBlock)onRequestClose
{
_onRequestClose = onRequestClose;
+ #if TARGET_OS_TV
if (_reactSubview) {
if (_onRequestClose && _menuButtonGestureRecognizer) {
[_reactSubview addGestureRecognizer:_menuButtonGestureRecognizer];
@@ -81,8 +105,8 @@ - (void)setOnRequestClose:(RCTDirectEventBlock)onRequestClose
[_reactSubview removeGestureRecognizer:_menuButtonGestureRecognizer];
}
}
+ #endif
}
-#endif
- (void)notifyForBoundsChange:(CGRect)newBounds
{
@@ -156,6 +180,13 @@ - (void)didUpdateReactSubviews
// Do nothing, as subview (singular) is managed by `insertReactSubview:atIndex:`
}
+- (void)presentationControllerDidDismiss:(UIPresentationController *)presentationController
+{
+ if (_onRequestClose) {
+ _onRequestClose(nil);
+ }
+}
+
- (void)dismissModalViewController
{
if (_isPresented) {
diff --git a/node_modules/react-native/React/Views/RCTModalHostViewManager.m b/node_modules/react-native/React/Views/RCTModalHostViewManager.m
index fa6f645..da7ca01 100644
--- a/node_modules/react-native/React/Views/RCTModalHostViewManager.m
+++ b/node_modules/react-native/React/Views/RCTModalHostViewManager.m
@@ -114,9 +114,6 @@ - (void)invalidate
RCT_EXPORT_VIEW_PROPERTY(identifier, NSNumber)
RCT_EXPORT_VIEW_PROPERTY(supportedOrientations, NSArray)
RCT_EXPORT_VIEW_PROPERTY(onOrientationChange, RCTDirectEventBlock)
-
-#if TARGET_OS_TV
RCT_EXPORT_VIEW_PROPERTY(onRequestClose, RCTDirectEventBlock)
-#endif
@end
diff --git a/node_modules/react-native/React/Views/RCTModalHostView.h b/node_modules/react-native/React/Views/RCTModalHostView.h
index 4e61886..2b8b6c0 100644
--- a/node_modules/react-native/React/Views/RCTModalHostView.h
+++ b/node_modules/react-native/React/Views/RCTModalHostView.h
@@ -17,7 +17,7 @@
@protocol RCTModalHostViewInteractor;
-@interface RCTModalHostView : UIView <RCTInvalidating>
+@interface RCTModalHostView : UIView <RCTInvalidating, UIAdaptivePresentationControllerDelegate>
@property (nonatomic, copy) NSString *animationType;
@property (nonatomic, assign) UIModalPresentationStyle presentationStyle;
@@ -31,9 +31,9 @@
@property (nonatomic, copy) NSArray<NSString *> *supportedOrientations;
@property (nonatomic, copy) RCTDirectEventBlock onOrientationChange;
+@property (nonatomic, copy) RCTDirectEventBlock onRequestClose;
#if TARGET_OS_TV
-@property (nonatomic, copy) RCTDirectEventBlock onRequestClose;
@property (nonatomic, strong) RCTTVRemoteHandler *tvRemoteHandler;
#endif
diff --git a/node_modules/react-native/React/Views/RCTModalHostView.m b/node_modules/react-native/React/Views/RCTModalHostView.m
index 6a15330..ec81912 100644
--- a/node_modules/react-native/React/Views/RCTModalHostView.m
+++ b/node_modules/react-native/React/Views/RCTModalHostView.m
@@ -41,6 +41,10 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge
if ((self = [super initWithFrame:CGRectZero])) {
_bridge = bridge;
_modalViewController = [RCTModalHostViewController new];
+ // Transparency breaks for overFullScreen in iOS < 13
+ if (@available(iOS 13.0, *)) {
+ _modalViewController.presentationController.delegate = self;
+ }
UIView *containerView = [UIView new];
containerView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
_modalViewController.view = containerView;
@@ -69,10 +73,12 @@ - (void)menuButtonPressed:(__unused UIGestureRecognizer *)gestureRecognizer
_onRequestClose(nil);
}
}
+#endif
- (void)setOnRequestClose:(RCTDirectEventBlock)onRequestClose
{
_onRequestClose = onRequestClose;
+ #if TARGET_OS_TV
if (_reactSubview) {
if (_onRequestClose && _menuButtonGestureRecognizer) {
[_reactSubview addGestureRecognizer:_menuButtonGestureRecognizer];
@@ -80,8 +86,8 @@ - (void)setOnRequestClose:(RCTDirectEventBlock)onRequestClose
[_reactSubview removeGestureRecognizer:_menuButtonGestureRecognizer];
}
}
+ #endif
}
-#endif
- (void)notifyForBoundsChange:(CGRect)newBounds
{
@@ -257,4 +263,31 @@ - (UIInterfaceOrientationMask)supportedOrientationsMask
}
#endif
+// MARK: - UIAdaptivePresentationControllerDelegate -
+
+// Method must be implemented, otherwise iOS defaults to 'automatic' (pageSheet on >= iOS 13.0)
+- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller traitCollection:(UITraitCollection *)traitCollection
+{
+ if (self.presentationStyle == UIModalPresentationFullScreen && self.isTransparent) {
+ return UIModalPresentationOverFullScreen;
+ }
+ return self.presentationStyle;
+}
+
+// Method must be implemented, otherwise iOS defaults to 'automatic' (pageSheet on >= iOS 13.0)
+- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller
+{
+ if (self.presentationStyle == UIModalPresentationFullScreen && self.isTransparent) {
+ return UIModalPresentationOverFullScreen;
+ }
+ return self.presentationStyle;
+}
+
+- (void)presentationControllerDidDismiss:(UIPresentationController *)presentationController
+{
+ if (_onRequestClose) {
+ _onRequestClose(nil);
+ }
+}
+
@end
diff --git a/node_modules/react-native/React/Views/RCTModalHostViewController.m b/node_modules/react-native/React/Views/RCTModalHostViewController.m
index 112bc17..d1158d8 100644
--- a/node_modules/react-native/React/Views/RCTModalHostViewController.m
+++ b/node_modules/react-native/React/Views/RCTModalHostViewController.m
@@ -24,12 +24,12 @@ - (instancetype)init
return nil;
}
-#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \
- __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
- if (@available(iOS 13.0, *)) {
- self.modalInPresentation = YES;
- }
-#endif
+//#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \
+// __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
+// if (@available(iOS 13.0, *)) {
+// self.modalInPresentation = YES;
+// }
+//#endif
#if !TARGET_OS_TV
_preferredStatusBarStyle = [RCTSharedApplication() statusBarStyle];
diff --git a/node_modules/react-native/React/Views/RCTModalHostViewManager.m b/node_modules/react-native/React/Views/RCTModalHostViewManager.m
index bafab9d..d56bb52 100644
--- a/node_modules/react-native/React/Views/RCTModalHostViewManager.m
+++ b/node_modules/react-native/React/Views/RCTModalHostViewManager.m
@@ -116,9 +116,6 @@ - (void)invalidate
RCT_EXPORT_VIEW_PROPERTY(identifier, NSNumber)
RCT_EXPORT_VIEW_PROPERTY(supportedOrientations, NSArray)
RCT_EXPORT_VIEW_PROPERTY(onOrientationChange, RCTDirectEventBlock)
-
-#if TARGET_OS_TV
RCT_EXPORT_VIEW_PROPERTY(onRequestClose, RCTDirectEventBlock)
-#endif
@end
@tsiory
Copy link

tsiory commented Jun 15, 2020

@r0b0t3d Thank you dude! your are my savior, thanks for your help! (I used v0.62.2 patch).

@sllvn
Copy link

sllvn commented Jul 15, 2020

Thanks much! Applied the 0.62.0 patch to RN 0.61.5 and it works great.

@marf
Copy link

marf commented Jul 17, 2020

Hello, can this patch be applied to RN 0.63.1 which is out now?

Thank you!

@r0b0t3d
Copy link
Author

r0b0t3d commented Jul 18, 2020

@marf I'm not sure. I'm still in 0.62.2 because got issue with babel-plugin-module-resolver in 0.63. You can try to edit directly in your code then run yarn patch-package react-native to create new patch for 0.63

@hanhtv204
Copy link

not working to RN 0.63.3 :(

@r0b0t3d
Copy link
Author

r0b0t3d commented Nov 30, 2020

@hanhtv204 Please check file react-native+0.63.3.patch

@dcosmin2003
Copy link

Anyone managed to make the patch for 0.64, please?

@MegaMaddin
Copy link

MegaMaddin commented May 13, 2021

Created patch for RN-0.64.1: react-native+0.64.1.patch

@timoisalive
Copy link

I'm assuming this patch does not work with Expo Managed workflow... Is this a feature or a bug that should be getting fixed in React Native?

Has anyone by chance tried RefreshControl inside a Modal with the patch, does it work like in the below post? Pull-to-refresh does not seem to work with plain Modal with presentationStyle="form/pageSheet" and ScrollView. 😢

https://sarunw.com/posts/uirefreshcontrol-with-new-card-style-modal/

@ceshm
Copy link

ceshm commented Jun 30, 2021

Created patch for RN-0.64.1: react-native+0.64.1.patch

Thanks! this also works for RN-0.64.2

@VishwaiOSDev
Copy link

Created patch for RN-0.64.1: react-native+0.64.1.patch

Thanks! this also works for RN-0.64.2

Can you please tell me how to use this patch?

@MegaMaddin
Copy link

Created patch for RN-0.64.1: react-native+0.64.1.patch

Thanks! this also works for RN-0.64.2

Can you please tell me how to use this patch?

By using https://github.com/ds300/patch-package.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment