diff --git a/React/Views/RCTModalHostView.h b/React/Views/RCTModalHostView.h index a04c37be2..07b995eb5 100644 --- a/React/Views/RCTModalHostView.h +++ b/React/Views/RCTModalHostView.h @@ -10,9 +10,13 @@ #import #import "RCTInvalidating.h" +#import "RCTModalHostViewManager.h" #import "RCTView.h" @class RCTBridge; +@class RCTModalHostViewController; + +@protocol RCTModalHostViewInteractor; @interface RCTModalHostView : UIView @@ -21,6 +25,15 @@ @property (nonatomic, copy) RCTDirectEventBlock onShow; +@property (nonatomic, weak) id delegate; + - (instancetype)initWithBridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER; @end + +@protocol RCTModalHostViewInteractor + +- (void)presentModalHostView:(RCTModalHostView *)modalHostView withViewController:(RCTModalHostViewController *)viewController animated:(BOOL)animated; +- (void)dismissModalHostView:(RCTModalHostView *)modalHostView withViewController:(RCTModalHostViewController *)viewController animated:(BOOL)animated; + +@end diff --git a/React/Views/RCTModalHostView.m b/React/Views/RCTModalHostView.m index 5b2f954ef..c622b1899 100644 --- a/React/Views/RCTModalHostView.m +++ b/React/Views/RCTModalHostView.m @@ -83,7 +83,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:coder) - (void)dismissModalViewController { if (_isPresented) { - [_modalViewController dismissViewControllerAnimated:[self hasAnimationType] completion:nil]; + [_delegate dismissModalHostView:self withViewController:_modalViewController animated:[self hasAnimationType]]; _isPresented = NO; } } @@ -100,11 +100,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:coder) } else if ([self.animationType isEqualToString:@"slide"]) { _modalViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical; } - [self.reactViewController presentViewController:_modalViewController animated:[self hasAnimationType] completion:^{ - if (self->_onShow) { - self->_onShow(nil); - } - }]; + [_delegate presentModalHostView:self withViewController:_modalViewController animated:[self hasAnimationType]]; _isPresented = YES; } } diff --git a/React/Views/RCTModalHostViewManager.h b/React/Views/RCTModalHostViewManager.h index fb5972d34..2ae57b3bc 100644 --- a/React/Views/RCTModalHostViewManager.h +++ b/React/Views/RCTModalHostViewManager.h @@ -11,6 +11,16 @@ #import "RCTInvalidating.h" +typedef void (^RCTModalViewInteractionBlock)(UIViewController *reactViewController, UIViewController *viewController, BOOL animated, dispatch_block_t completionBlock); + @interface RCTModalHostViewManager : RCTViewManager +/** + * `presentationBlock` and `dismissalBlock` allow you to control how a Modal interacts with your case, + * e.g. in case you have a native navigator that has its own way to display a modal. + * If these are not specified, it falls back to the UIViewController standard way of presenting. + */ +@property (nonatomic, strong) RCTModalViewInteractionBlock presentationBlock; +@property (nonatomic, strong) RCTModalViewInteractionBlock dismissalBlock; + @end diff --git a/React/Views/RCTModalHostViewManager.m b/React/Views/RCTModalHostViewManager.m index a7227247d..ccd0cdca0 100644 --- a/React/Views/RCTModalHostViewManager.m +++ b/React/Views/RCTModalHostViewManager.m @@ -11,6 +11,7 @@ #import "RCTBridge.h" #import "RCTModalHostView.h" +#import "RCTModalHostViewController.h" #import "RCTTouchHandler.h" #import "RCTShadowView.h" #import "RCTUtils.h" @@ -32,6 +33,10 @@ @end +@interface RCTModalHostViewManager () + +@end + @implementation RCTModalHostViewManager { NSHashTable *_hostViews; @@ -41,7 +46,8 @@ RCT_EXPORT_MODULE() - (UIView *)view { - UIView *view = [[RCTModalHostView alloc] initWithBridge:self.bridge]; + RCTModalHostView *view = [[RCTModalHostView alloc] initWithBridge:self.bridge]; + view.delegate = self; if (!_hostViews) { _hostViews = [NSHashTable weakObjectsHashTable]; } @@ -49,6 +55,30 @@ RCT_EXPORT_MODULE() 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 { + [[modalHostView reactViewController] presentViewController:viewController animated:animated completion:completionBlock]; + } +} + +- (void)dismissModalHostView:(RCTModalHostView *)modalHostView withViewController:(RCTModalHostViewController *)viewController animated:(BOOL)animated +{ + if (_dismissalBlock) { + _dismissalBlock([modalHostView reactViewController], viewController, animated, nil); + } else { + [viewController dismissViewControllerAnimated:animated completion:nil]; + } +} + + - (RCTShadowView *)shadowView { return [RCTModalHostShadowView new];