Skip to content

Commit 6d00239

Browse files
kokealloy
authored andcommitted
Implement onRequestClose for iOS 13+ modals (#27618)
Summary: Starting on iOS 13, a View Controller presented modally will have a "bottom sheet" style unless it's explicitly presented full screen. Before this, modals on iOS were only being dismissed programatically by setting `visible={false}`. However, now that the dismissal can happen on the OS side, we need a callback to be able to update the state. This PR reuses the `onRequestClose` prop already available for tvOS and Android, and makes it work on iOS for this use case. Should fix #26892 ## Changelog [iOS] [Added] - Add support for onRequestClose prop to Modal on iOS 13+ Pull Request resolved: #27618 Test Plan: I tested this using the RNTester app with the Modal example: 1. Select any presentation style other than the full screen ones 2. Tap Present and the modal is presented 3. Swipe down on the presented modal until dismissed 4. Tap Present again and a second modal should be presented ![Screen Recording 2019-12-26 at 14 05 33](https://user-images.githubusercontent.com/8739/71477208-0ac88c80-27e9-11ea-9342-8631426a9b80.gif) Differential Revision: D19235758 Pulled By: shergin fbshipit-source-id: c0f1d946c77ce8d1baab209eaef7eb64697851df
1 parent cae662b commit 6d00239

File tree

6 files changed

+38
-8
lines changed

6 files changed

+38
-8
lines changed

Libraries/Modal/Modal.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ export type Props = $ReadOnly<{|
9595

9696
/**
9797
* The `onRequestClose` callback is called when the user taps the hardware
98-
* back button on Android or the menu button on Apple TV.
98+
* back button on Android, the menu button on Apple TV, or a modal is dismissed
99+
* with a gesture on iOS 13+.
99100
*
100101
* This is required on Apple TV and Android.
101102
*

Libraries/Modal/RCTModalHostViewNativeComponent.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ type NativeProps = $ReadOnly<{|
7070

7171
/**
7272
* The `onRequestClose` callback is called when the user taps the hardware
73-
* back button on Android or the menu button on Apple TV.
73+
* back button on Android, the menu button on Apple TV, or a modal is dismissed
74+
* with a gesture on iOS 13+.
7475
*
7576
* This is required on Apple TV and Android.
7677
*

React/Fabric/Mounting/ComponentViews/Modal/RCTModalHostViewComponentView.mm

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,9 @@ static ModalHostViewOnOrientationChangeStruct onOrientationChangeStruct(CGRect r
9191
return {orientation};
9292
}
9393

94-
@interface RCTModalHostViewComponentView () <RCTFabricModalHostViewControllerDelegate>
94+
@interface RCTModalHostViewComponentView () <
95+
RCTFabricModalHostViewControllerDelegate,
96+
UIAdaptivePresentationControllerDelegate>
9597

9698
@end
9799

@@ -110,6 +112,7 @@ - (instancetype)initWithFrame:(CGRect)frame
110112
_viewController = [RCTFabricModalHostViewController new];
111113
_viewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
112114
_viewController.delegate = self;
115+
_viewController.presentationController.delegate = self;
113116
}
114117

115118
return self;
@@ -214,4 +217,17 @@ - (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childCompo
214217
[childComponentView removeFromSuperview];
215218
}
216219

220+
#pragma mark - UIAdaptivePresentationControllerDelegate
221+
222+
- (void)presentationControllerDidDismiss:(UIPresentationController *)presentationController
223+
{
224+
if (!_eventEmitter) {
225+
return;
226+
}
227+
228+
assert(std::dynamic_pointer_cast<ModalHostViewEventEmitter const>(_eventEmitter));
229+
auto eventEmitter = std::static_pointer_cast<ModalHostViewEventEmitter const>(_eventEmitter);
230+
eventEmitter->onRequestClose({});
231+
}
232+
217233
@end

React/Views/RCTModalHostView.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@
3232
@property (nonatomic, copy) NSArray<NSString *> *supportedOrientations;
3333
@property (nonatomic, copy) RCTDirectEventBlock onOrientationChange;
3434

35-
#if TARGET_OS_TV
3635
@property (nonatomic, copy) RCTDirectEventBlock onRequestClose;
36+
37+
#if TARGET_OS_TV
3738
@property (nonatomic, strong) RCTTVRemoteHandler *tvRemoteHandler;
3839
#endif
3940

React/Views/RCTModalHostView.m

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
#import "RCTTVRemoteHandler.h"
2121
#endif
2222

23+
@interface RCTModalHostView () <UIAdaptivePresentationControllerDelegate>
24+
25+
@end
26+
2327
@implementation RCTModalHostView
2428
{
2529
__weak RCTBridge *_bridge;
@@ -46,6 +50,7 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge
4650
UIView *containerView = [UIView new];
4751
containerView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
4852
_modalViewController.view = containerView;
53+
_modalViewController.presentationController.delegate = self;
4954
_touchHandler = [[RCTTouchHandler alloc] initWithBridge:bridge];
5055
#if TARGET_OS_TV
5156
_menuButtonGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(menuButtonPressed:)];
@@ -70,19 +75,21 @@ - (void)menuButtonPressed:(__unused UIGestureRecognizer *)gestureRecognizer
7075
_onRequestClose(nil);
7176
}
7277
}
78+
#endif
7379

7480
- (void)setOnRequestClose:(RCTDirectEventBlock)onRequestClose
7581
{
7682
_onRequestClose = onRequestClose;
83+
#if TARGET_OS_TV
7784
if (_reactSubview) {
7885
if (_onRequestClose && _menuButtonGestureRecognizer) {
7986
[_reactSubview addGestureRecognizer:_menuButtonGestureRecognizer];
8087
} else {
8188
[_reactSubview removeGestureRecognizer:_menuButtonGestureRecognizer];
8289
}
8390
}
91+
#endif
8492
}
85-
#endif
8693

8794
- (void)notifyForBoundsChange:(CGRect)newBounds
8895
{
@@ -257,4 +264,11 @@ - (UIInterfaceOrientationMask)supportedOrientationsMask
257264
}
258265
#endif
259266

267+
- (void)presentationControllerDidDismiss:(UIPresentationController *)presentationController
268+
{
269+
if (_onRequestClose) {
270+
_onRequestClose(nil);
271+
}
272+
}
273+
260274
@end

React/Views/RCTModalHostViewManager.m

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,6 @@ - (void)invalidate
108108
RCT_EXPORT_VIEW_PROPERTY(identifier, NSNumber)
109109
RCT_EXPORT_VIEW_PROPERTY(supportedOrientations, NSArray)
110110
RCT_EXPORT_VIEW_PROPERTY(onOrientationChange, RCTDirectEventBlock)
111-
112-
#if TARGET_OS_TV
113111
RCT_EXPORT_VIEW_PROPERTY(onRequestClose, RCTDirectEventBlock)
114-
#endif
115112

116113
@end

0 commit comments

Comments
 (0)