Skip to content

Commit 8e5fac8

Browse files
kokefacebook-github-bot
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 6be37d8 commit 8e5fac8

File tree

6 files changed

+38
-8
lines changed

6 files changed

+38
-8
lines changed

Libraries/Modal/Modal.js

+2-1
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

+2-1
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

+17-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,9 @@ static UIModalPresentationStyle presentationConfiguration(ModalHostViewProps con
9494
return {orientation};
9595
}
9696

97-
@interface RCTModalHostViewComponentView () <RCTFabricModalHostViewControllerDelegate>
97+
@interface RCTModalHostViewComponentView () <
98+
RCTFabricModalHostViewControllerDelegate,
99+
UIAdaptivePresentationControllerDelegate>
98100

99101
@end
100102

@@ -113,6 +115,7 @@ - (instancetype)initWithFrame:(CGRect)frame
113115
_viewController = [RCTFabricModalHostViewController new];
114116
_viewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
115117
_viewController.delegate = self;
118+
_viewController.presentationController.delegate = self;
116119
}
117120

118121
return self;
@@ -217,6 +220,19 @@ - (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childCompo
217220
[childComponentView removeFromSuperview];
218221
}
219222

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

222238
Class<RCTComponentViewProtocol> RCTModalHostViewCls(void)

React/Views/RCTModalHostView.h

+2-1
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

+15-1
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

-3
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)