Files
react-native/React/Views/RCTModalHostViewManager.m
T
Mi-ZAZ 8933724d7d Update RCTModalHostViewManager.m (#29745)
Summary:
Fix a issue that RCTModalHostView can't be dismissed while being presented

Steps To Reproduce
A native modal presented view controller is being dismissed before the first screen shows.
A RCTModalHostView is presented when the first screen shows.
The RCTModalHostView will be dismissed after an asynchronous callback.
If the callback was called before the completion of the presenting animation, the RCTModalHostView will not be dismissed.

## Changelog

[iOS] [Fixed] - Fix that RCTModalHostView can't be dismissed while being presented

Pull Request resolved: https://github.com/facebook/react-native/pull/29745

Reviewed By: shergin

Differential Revision: D23566487

Pulled By: sammy-SC

fbshipit-source-id: bd95f200b79fa75e2387e402091d58c0f538759c
2020-09-09 06:41:06 -07:00

140 lines
4.1 KiB
Objective-C

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTModalHostViewManager.h"
#import "RCTBridge.h"
#import "RCTModalHostView.h"
#import "RCTModalHostViewController.h"
#import "RCTShadowView.h"
#import "RCTUtils.h"
@implementation RCTConvert (RCTModalHostView)
RCT_ENUM_CONVERTER(
UIModalPresentationStyle,
(@{
@"fullScreen" : @(UIModalPresentationFullScreen),
#if !TARGET_OS_TV
@"pageSheet" : @(UIModalPresentationPageSheet),
@"formSheet" : @(UIModalPresentationFormSheet),
#endif
@"overFullScreen" : @(UIModalPresentationOverFullScreen),
}),
UIModalPresentationFullScreen,
integerValue)
@end
@interface RCTModalHostShadowView : RCTShadowView
@end
@implementation RCTModalHostShadowView
- (void)insertReactSubview:(id<RCTComponent>)subview atIndex:(NSInteger)atIndex
{
[super insertReactSubview:subview atIndex:atIndex];
if ([subview isKindOfClass:[RCTShadowView class]]) {
((RCTShadowView *)subview).size = RCTScreenSize();
}
}
@end
@interface RCTModalHostViewManager () <RCTModalHostViewInteractor>
@property (nonatomic, copy) dispatch_block_t dismissWaitingBlock;
@end
@implementation RCTModalHostViewManager {
NSPointerArray *_hostViews;
}
RCT_EXPORT_MODULE()
- (UIView *)view
{
RCTModalHostView *view = [[RCTModalHostView alloc] initWithBridge:self.bridge];
view.delegate = self;
if (!_hostViews) {
_hostViews = [NSPointerArray weakObjectsPointerArray];
}
[_hostViews addPointer:(__bridge void *)view];
return view;
}
- (void)presentModalHostView:(RCTModalHostView *)modalHostView
withViewController:(RCTModalHostViewController *)viewController
animated:(BOOL)animated
{
dispatch_block_t completionBlock = ^{
if (modalHostView.onShow) {
modalHostView.onShow(nil);
}
};
if (_presentationBlock) {
_presentationBlock([modalHostView reactViewController], viewController, animated, completionBlock);
} else {
__weak typeof(self) weakself = self;
[[modalHostView reactViewController] presentViewController:viewController
animated:animated
completion:^{
!completionBlock ?: completionBlock();
__strong typeof(weakself) strongself = weakself;
!strongself.dismissWaitingBlock
?: strongself.dismissWaitingBlock();
strongself.dismissWaitingBlock = nil;
}];
}
}
- (void)dismissModalHostView:(RCTModalHostView *)modalHostView
withViewController:(RCTModalHostViewController *)viewController
animated:(BOOL)animated
{
if (_dismissalBlock) {
_dismissalBlock([modalHostView reactViewController], viewController, animated, nil);
} else {
self.dismissWaitingBlock = ^{
[viewController.presentingViewController dismissViewControllerAnimated:animated completion:nil];
};
if (viewController.presentingViewController) {
self.dismissWaitingBlock();
self.dismissWaitingBlock = nil;
}
}
}
- (RCTShadowView *)shadowView
{
return [RCTModalHostShadowView new];
}
- (void)invalidate
{
for (RCTModalHostView *hostView in _hostViews) {
[hostView invalidate];
}
_hostViews = nil;
}
RCT_EXPORT_VIEW_PROPERTY(animationType, NSString)
RCT_EXPORT_VIEW_PROPERTY(presentationStyle, UIModalPresentationStyle)
RCT_EXPORT_VIEW_PROPERTY(transparent, BOOL)
RCT_EXPORT_VIEW_PROPERTY(onShow, RCTDirectEventBlock)
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