Allow <Modal /> to be configured with a custom presentation/dismissal block

Reviewed By: javache, majak

Differential Revision: D3751545

fbshipit-source-id: 4cf420769f7939289c0b0b70ae784328df8e2bbf
This commit is contained in:
Mehdi Mulani 2016-08-23 16:50:23 -07:00 committed by Facebook Github Bot 0
parent cd1d652af4
commit d8b2bab794
4 changed files with 56 additions and 7 deletions

View File

@ -10,9 +10,13 @@
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import "RCTInvalidating.h" #import "RCTInvalidating.h"
#import "RCTModalHostViewManager.h"
#import "RCTView.h" #import "RCTView.h"
@class RCTBridge; @class RCTBridge;
@class RCTModalHostViewController;
@protocol RCTModalHostViewInteractor;
@interface RCTModalHostView : UIView <RCTInvalidating> @interface RCTModalHostView : UIView <RCTInvalidating>
@ -21,6 +25,15 @@
@property (nonatomic, copy) RCTDirectEventBlock onShow; @property (nonatomic, copy) RCTDirectEventBlock onShow;
@property (nonatomic, weak) id<RCTModalHostViewInteractor> delegate;
- (instancetype)initWithBridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER; - (instancetype)initWithBridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
@end @end
@protocol RCTModalHostViewInteractor <NSObject>
- (void)presentModalHostView:(RCTModalHostView *)modalHostView withViewController:(RCTModalHostViewController *)viewController animated:(BOOL)animated;
- (void)dismissModalHostView:(RCTModalHostView *)modalHostView withViewController:(RCTModalHostViewController *)viewController animated:(BOOL)animated;
@end

View File

@ -83,7 +83,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:coder)
- (void)dismissModalViewController - (void)dismissModalViewController
{ {
if (_isPresented) { if (_isPresented) {
[_modalViewController dismissViewControllerAnimated:[self hasAnimationType] completion:nil]; [_delegate dismissModalHostView:self withViewController:_modalViewController animated:[self hasAnimationType]];
_isPresented = NO; _isPresented = NO;
} }
} }
@ -100,11 +100,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:coder)
} else if ([self.animationType isEqualToString:@"slide"]) { } else if ([self.animationType isEqualToString:@"slide"]) {
_modalViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical; _modalViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
} }
[self.reactViewController presentViewController:_modalViewController animated:[self hasAnimationType] completion:^{ [_delegate presentModalHostView:self withViewController:_modalViewController animated:[self hasAnimationType]];
if (self->_onShow) {
self->_onShow(nil);
}
}];
_isPresented = YES; _isPresented = YES;
} }
} }

View File

@ -11,6 +11,16 @@
#import "RCTInvalidating.h" #import "RCTInvalidating.h"
typedef void (^RCTModalViewInteractionBlock)(UIViewController *reactViewController, UIViewController *viewController, BOOL animated, dispatch_block_t completionBlock);
@interface RCTModalHostViewManager : RCTViewManager <RCTInvalidating> @interface RCTModalHostViewManager : RCTViewManager <RCTInvalidating>
/**
* `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 @end

View File

@ -11,6 +11,7 @@
#import "RCTBridge.h" #import "RCTBridge.h"
#import "RCTModalHostView.h" #import "RCTModalHostView.h"
#import "RCTModalHostViewController.h"
#import "RCTTouchHandler.h" #import "RCTTouchHandler.h"
#import "RCTShadowView.h" #import "RCTShadowView.h"
#import "RCTUtils.h" #import "RCTUtils.h"
@ -32,6 +33,10 @@
@end @end
@interface RCTModalHostViewManager () <RCTModalHostViewInteractor>
@end
@implementation RCTModalHostViewManager @implementation RCTModalHostViewManager
{ {
NSHashTable *_hostViews; NSHashTable *_hostViews;
@ -41,7 +46,8 @@ RCT_EXPORT_MODULE()
- (UIView *)view - (UIView *)view
{ {
UIView *view = [[RCTModalHostView alloc] initWithBridge:self.bridge]; RCTModalHostView *view = [[RCTModalHostView alloc] initWithBridge:self.bridge];
view.delegate = self;
if (!_hostViews) { if (!_hostViews) {
_hostViews = [NSHashTable weakObjectsHashTable]; _hostViews = [NSHashTable weakObjectsHashTable];
} }
@ -49,6 +55,30 @@ RCT_EXPORT_MODULE()
return 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 {
[[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 - (RCTShadowView *)shadowView
{ {
return [RCTModalHostShadowView new]; return [RCTModalHostShadowView new];