Skip to content

Commit

Permalink
Implement onRequestClose for iOS 13+ modals (#27618)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
koke authored and facebook-github-bot committed Feb 6, 2020
1 parent 6be37d8 commit 8e5fac8
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 8 deletions.
3 changes: 2 additions & 1 deletion Libraries/Modal/Modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ export type Props = $ReadOnly<{|

/**
* The `onRequestClose` callback is called when the user taps the hardware
* back button on Android or the menu button on Apple TV.
* back button on Android, the menu button on Apple TV, or a modal is dismissed
* with a gesture on iOS 13+.
*
* This is required on Apple TV and Android.
*
Expand Down
3 changes: 2 additions & 1 deletion Libraries/Modal/RCTModalHostViewNativeComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ type NativeProps = $ReadOnly<{|

/**
* The `onRequestClose` callback is called when the user taps the hardware
* back button on Android or the menu button on Apple TV.
* back button on Android, the menu button on Apple TV, or a modal is dismissed
* with a gesture on iOS 13+.
*
* This is required on Apple TV and Android.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,9 @@ static UIModalPresentationStyle presentationConfiguration(ModalHostViewProps con
return {orientation};
}

@interface RCTModalHostViewComponentView () <RCTFabricModalHostViewControllerDelegate>
@interface RCTModalHostViewComponentView () <
RCTFabricModalHostViewControllerDelegate,
UIAdaptivePresentationControllerDelegate>

@end

Expand All @@ -113,6 +115,7 @@ - (instancetype)initWithFrame:(CGRect)frame
_viewController = [RCTFabricModalHostViewController new];
_viewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
_viewController.delegate = self;
_viewController.presentationController.delegate = self;
}

return self;
Expand Down Expand Up @@ -217,6 +220,19 @@ - (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childCompo
[childComponentView removeFromSuperview];
}

#pragma mark - UIAdaptivePresentationControllerDelegate

- (void)presentationControllerDidDismiss:(UIPresentationController *)presentationController
{
if (!_eventEmitter) {
return;
}

assert(std::dynamic_pointer_cast<ModalHostViewEventEmitter const>(_eventEmitter));
auto eventEmitter = std::static_pointer_cast<ModalHostViewEventEmitter const>(_eventEmitter);
eventEmitter->onRequestClose({});
}

@end

Class<RCTComponentViewProtocol> RCTModalHostViewCls(void)
Expand Down
3 changes: 2 additions & 1 deletion React/Views/RCTModalHostView.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@
@property (nonatomic, copy) NSArray<NSString *> *supportedOrientations;
@property (nonatomic, copy) RCTDirectEventBlock onOrientationChange;

#if TARGET_OS_TV
@property (nonatomic, copy) RCTDirectEventBlock onRequestClose;

#if TARGET_OS_TV
@property (nonatomic, strong) RCTTVRemoteHandler *tvRemoteHandler;
#endif

Expand Down
16 changes: 15 additions & 1 deletion React/Views/RCTModalHostView.m
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
#import "RCTTVRemoteHandler.h"
#endif

@interface RCTModalHostView () <UIAdaptivePresentationControllerDelegate>

@end

@implementation RCTModalHostView
{
__weak RCTBridge *_bridge;
Expand All @@ -46,6 +50,7 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge
UIView *containerView = [UIView new];
containerView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
_modalViewController.view = containerView;
_modalViewController.presentationController.delegate = self;
_touchHandler = [[RCTTouchHandler alloc] initWithBridge:bridge];
#if TARGET_OS_TV
_menuButtonGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(menuButtonPressed:)];
Expand All @@ -70,19 +75,21 @@ - (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];
} else {
[_reactSubview removeGestureRecognizer:_menuButtonGestureRecognizer];
}
}
#endif
}
#endif

- (void)notifyForBoundsChange:(CGRect)newBounds
{
Expand Down Expand Up @@ -257,4 +264,11 @@ - (UIInterfaceOrientationMask)supportedOrientationsMask
}
#endif

- (void)presentationControllerDidDismiss:(UIPresentationController *)presentationController
{
if (_onRequestClose) {
_onRequestClose(nil);
}
}

@end
3 changes: 0 additions & 3 deletions React/Views/RCTModalHostViewManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 8e5fac8

Please sign in to comment.