From 0f149339487ae68cd740f6295cc94a04ff8cf2f5 Mon Sep 17 00:00:00 2001 From: Alexsander Akers Date: Thu, 13 Aug 2015 15:09:10 -0100 Subject: [PATCH] Enable transparent modal presentation with Summary: Enable transparent modal backgrounds using `UIModalPresentationCustom` modal presentation style. --- Examples/UIExplorer/ModalExample.js | 137 ++++++++++++++++++++------ Libraries/Modal/Modal.js | 17 +++- React/Views/RCTModalHostView.h | 5 +- React/Views/RCTModalHostView.m | 17 ++++ React/Views/RCTModalHostViewManager.h | 4 +- React/Views/RCTModalHostViewManager.m | 25 ++++- 6 files changed, 168 insertions(+), 37 deletions(-) diff --git a/Examples/UIExplorer/ModalExample.js b/Examples/UIExplorer/ModalExample.js index 37d2cc245..3202cb622 100644 --- a/Examples/UIExplorer/ModalExample.js +++ b/Examples/UIExplorer/ModalExample.js @@ -19,6 +19,7 @@ var React = require('react-native'); var { Modal, StyleSheet, + SwitchIOS, Text, TouchableHighlight, View, @@ -29,53 +30,98 @@ exports.framework = 'React'; exports.title = ''; exports.description = 'Component for presenting modal views.'; -var ModalExample = React.createClass({ - getInitialState: function() { +var Button = React.createClass({ + getInitialState() { return { - openModal: null, + active: false, }; }, - _closeModal: function() { - this.setState({openModal: null}); + _onHighlight() { + this.setState({active: true}); }, - _openAnimatedModal: function() { - this.setState({openModal: 'animated'}); + _onUnhighlight() { + this.setState({active: false}); }, - _openNotAnimatedModal: function() { - this.setState({openModal: 'not-animated'}); + render() { + var colorStyle = { + color: this.state.active ? '#fff' : '#000', + }; + return ( + + {this.props.children} + + ); + } +}); + +var ModalExample = React.createClass({ + getInitialState() { + return { + animated: true, + modalVisible: false, + transparent: false, + }; }, - render: function() { + _setModalVisible(visible) { + this.setState({modalVisible: visible}); + }, + + _toggleAnimated() { + this.setState({animated: !this.state.animated}); + }, + + _toggleTransparent() { + this.setState({transparent: !this.state.transparent}); + }, + + render() { + var modalBackgroundStyle = { + backgroundColor: this.state.transparent ? 'rgba(0, 0, 0, 0.5)' : '#f5fcff', + }; + var innerContainerTransparentStyle = this.state.transparent + ? {backgroundColor: '#fff', padding: 20} + : null; + return ( - - - This modal was presented with animation. - - Close - + + + + This modal was presented {this.state.animated ? 'with' : 'without'} animation. + + - - - This modal was presented immediately, without animation. - - Close - - - + + Animated + + - - Present Animated - + + Transparent + + - - Present Without Animation - + ); }, @@ -91,9 +137,36 @@ exports.examples = [ var styles = StyleSheet.create({ container: { - alignItems: 'center', - backgroundColor: '#f5fcff', flex: 1, justifyContent: 'center', + padding: 20, + }, + innerContainer: { + borderRadius: 10, + }, + row: { + alignItems: 'center', + flex: 1, + flexDirection: 'row', + marginBottom: 20, + }, + rowTitle: { + flex: 1, + fontWeight: 'bold', + }, + button: { + borderRadius: 5, + flex: 1, + height: 44, + justifyContent: 'center', + overflow: 'hidden', + }, + buttonText: { + fontSize: 18, + margin: 5, + textAlign: 'center', + }, + modalButton: { + marginTop: 10, }, }); diff --git a/Libraries/Modal/Modal.js b/Libraries/Modal/Modal.js index 23bf730ec..2063f0fdd 100644 --- a/Libraries/Modal/Modal.js +++ b/Libraries/Modal/Modal.js @@ -11,6 +11,7 @@ */ 'use strict'; +var PropTypes = require('ReactPropTypes'); var React = require('React'); var StyleSheet = require('StyleSheet'); var View = require('View'); @@ -24,9 +25,16 @@ class Modal extends React.Component { return null; } + if (this.props.transparent) { + var containerBackgroundColor = {backgroundColor: 'transparent'}; + } + return ( - - + + {this.props.children} @@ -34,6 +42,11 @@ class Modal extends React.Component { } } +Modal.propTypes = { + animated: PropTypes.bool, + transparent: PropTypes.bool, +}; + var styles = StyleSheet.create({ modal: { position: 'absolute', diff --git a/React/Views/RCTModalHostView.h b/React/Views/RCTModalHostView.h index a39df2815..cafe771c8 100644 --- a/React/Views/RCTModalHostView.h +++ b/React/Views/RCTModalHostView.h @@ -9,11 +9,14 @@ #import +#import "RCTInvalidating.h" + @class RCTBridge; -@interface RCTModalHostView : UIView +@interface RCTModalHostView : UIView @property (nonatomic, assign, getter=isAnimated) BOOL animated; +@property (nonatomic, assign, getter=isTransparent) BOOL transparent; - (instancetype)initWithBridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER; diff --git a/React/Views/RCTModalHostView.m b/React/Views/RCTModalHostView.m index 0322e02ca..a4d1db93e 100644 --- a/React/Views/RCTModalHostView.m +++ b/React/Views/RCTModalHostView.m @@ -81,4 +81,21 @@ RCT_NOT_IMPLEMENTED(-initWithCoder:coder) } } +- (void)invalidate +{ + dispatch_async(dispatch_get_main_queue(), ^{ + [_modalViewController dismissViewControllerAnimated:self.animated completion:nil]; + }); +} + +- (BOOL)isTransparent +{ + return _modalViewController.modalPresentationStyle == UIModalPresentationCustom; +} + +- (void)setTransparent:(BOOL)transparent +{ + _modalViewController.modalPresentationStyle = transparent ? UIModalPresentationCustom : UIModalPresentationFullScreen; +} + @end diff --git a/React/Views/RCTModalHostViewManager.h b/React/Views/RCTModalHostViewManager.h index e47794542..fb5972d34 100644 --- a/React/Views/RCTModalHostViewManager.h +++ b/React/Views/RCTModalHostViewManager.h @@ -9,6 +9,8 @@ #import "RCTViewManager.h" -@interface RCTModalHostViewManager : RCTViewManager +#import "RCTInvalidating.h" + +@interface RCTModalHostViewManager : RCTViewManager @end diff --git a/React/Views/RCTModalHostViewManager.m b/React/Views/RCTModalHostViewManager.m index 458e65081..3ad022b21 100644 --- a/React/Views/RCTModalHostViewManager.m +++ b/React/Views/RCTModalHostViewManager.m @@ -14,14 +14,37 @@ #import "RCTTouchHandler.h" @implementation RCTModalHostViewManager +{ + NSHashTable *_hostViews; +} RCT_EXPORT_MODULE() +- (instancetype)init +{ + if ((self = [super init])) { + _hostViews = [NSHashTable weakObjectsHashTable]; + } + + return self; +} + - (UIView *)view { - return [[RCTModalHostView alloc] initWithBridge:self.bridge]; + UIView *view = [[RCTModalHostView alloc] initWithBridge:self.bridge]; + [_hostViews addObject:view]; + return view; +} + +- (void)invalidate +{ + for (RCTModalHostView *hostView in _hostViews) { + [hostView invalidate]; + } + [_hostViews removeAllObjects]; } RCT_EXPORT_VIEW_PROPERTY(animated, BOOL) +RCT_EXPORT_VIEW_PROPERTY(transparent, BOOL) @end