Skip to content

Commit 2bb1c26

Browse files
jemise111Facebook Github Bot 1
authored and
Facebook Github Bot 1
committed
Modal Animation Types
Summary: Currently the Modal component uses the slide up / down animation for presenting and hiding the Modal with no options. This PR gives users a choice to use a fade in / out animation or the current slide animation (slide is the default). Android and iOS. ![](http://g.recordit.co/nfJSg487Ox.gif) ![](http://g.recordit.co/QHGDuUFbPy.gif) I've updated the UIExplorer and documentation. ![image](https://cloud.githubusercontent.com/assets/4265163/14743130/0bd8282c-086e-11e6-93eb-3d344431337d.png) Thanks! Closes #7156 Differential Revision: D3237809 Pulled By: javache fb-gh-sync-id: 813e56ada8b19990dc5018527dc3a81b2c8b349a fbshipit-source-id: 813e56ada8b19990dc5018527dc3a81b2c8b349a
1 parent b5f14ea commit 2bb1c26

File tree

10 files changed

+88
-26
lines changed

10 files changed

+88
-26
lines changed

Examples/UIExplorer/ModalExample.js

+18-8
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ var Button = React.createClass({
6666
var ModalExample = React.createClass({
6767
getInitialState() {
6868
return {
69-
animated: true,
69+
animationType: 'none',
7070
modalVisible: false,
7171
transparent: false,
7272
};
@@ -76,8 +76,8 @@ var ModalExample = React.createClass({
7676
this.setState({modalVisible: visible});
7777
},
7878

79-
_toggleAnimated() {
80-
this.setState({animated: !this.state.animated});
79+
_setAnimationType(type) {
80+
this.setState({animationType: type});
8181
},
8282

8383
_toggleTransparent() {
@@ -91,18 +91,21 @@ var ModalExample = React.createClass({
9191
var innerContainerTransparentStyle = this.state.transparent
9292
? {backgroundColor: '#fff', padding: 20}
9393
: null;
94+
var activeButtonStyle = {
95+
backgroundColor: '#ddd'
96+
};
9497

9598
return (
9699
<View>
97100
<Modal
98-
animated={this.state.animated}
101+
animationType={this.state.animationType}
99102
transparent={this.state.transparent}
100103
visible={this.state.modalVisible}
101104
onRequestClose={() => {this._setModalVisible(false)}}
102105
>
103106
<View style={[styles.container, modalBackgroundStyle]}>
104107
<View style={[styles.innerContainer, innerContainerTransparentStyle]}>
105-
<Text>This modal was presented {this.state.animated ? 'with' : 'without'} animation.</Text>
108+
<Text>This modal was presented {this.state.animationType === 'none' ? 'without' : 'with'} animation.</Text>
106109
<Button
107110
onPress={this._setModalVisible.bind(this, false)}
108111
style={styles.modalButton}>
@@ -111,10 +114,17 @@ var ModalExample = React.createClass({
111114
</View>
112115
</View>
113116
</Modal>
114-
115117
<View style={styles.row}>
116-
<Text style={styles.rowTitle}>Animated</Text>
117-
<Switch value={this.state.animated} onValueChange={this._toggleAnimated} />
118+
<Text style={styles.rowTitle}>Animation Type</Text>
119+
<Button onPress={this._setAnimationType.bind(this, 'none')} style={this.state.animationType === 'none' ? activeButtonStyle : {}}>
120+
none
121+
</Button>
122+
<Button onPress={this._setAnimationType.bind(this, 'slide')} style={this.state.animationType === 'slide' ? activeButtonStyle : {}}>
123+
slide
124+
</Button>
125+
<Button onPress={this._setAnimationType.bind(this, 'fade')} style={this.state.animationType === 'fade' ? activeButtonStyle : {}}>
126+
fade
127+
</Button>
118128
</View>
119129

120130
<View style={styles.row}>

Libraries/Modal/Modal.js

+17-3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const PropTypes = require('ReactPropTypes');
1616
const React = require('React');
1717
const StyleSheet = require('StyleSheet');
1818
const View = require('View');
19+
const deprecatedPropType = require('deprecatedPropType');
1920

2021
const requireNativeComponent = require('requireNativeComponent');
2122
const RCTModalHostView = requireNativeComponent('RCTModalHostView', null);
@@ -35,7 +36,11 @@ const RCTModalHostView = requireNativeComponent('RCTModalHostView', null);
3536
*/
3637
class Modal extends React.Component {
3738
static propTypes = {
38-
animated: PropTypes.bool,
39+
animated: deprecatedPropType(
40+
PropTypes.bool,
41+
'Use the `animationType` prop instead.'
42+
),
43+
animationType: PropTypes.oneOf(['none', 'slide', 'fade']),
3944
transparent: PropTypes.bool,
4045
visible: PropTypes.bool,
4146
onRequestClose: Platform.OS === 'android' ? PropTypes.func.isRequired : PropTypes.func,
@@ -55,9 +60,18 @@ class Modal extends React.Component {
5560
backgroundColor: this.props.transparent ? 'transparent' : 'white',
5661
};
5762

63+
let animationType = this.props.animationType;
64+
if (!animationType) {
65+
// manually setting default prop here to keep support for the deprecated 'animated' prop
66+
animationType = 'none';
67+
if (this.props.animated) {
68+
animationType = 'slide';
69+
}
70+
}
71+
5872
return (
5973
<RCTModalHostView
60-
animated={this.props.animated}
74+
animationType={animationType}
6175
transparent={this.props.transparent}
6276
onRequestClose={this.props.onRequestClose}
6377
onShow={this.props.onShow}
@@ -88,4 +102,4 @@ const styles = StyleSheet.create({
88102
}
89103
});
90104

91-
module.exports = Modal;
105+
module.exports = Modal;

React/Views/RCTModalHostView.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
@interface RCTModalHostView : UIView <RCTInvalidating>
1818

19-
@property (nonatomic, assign, getter=isAnimated) BOOL animated;
19+
@property (nonatomic, copy) NSString *animationType;
2020
@property (nonatomic, assign, getter=isTransparent) BOOL transparent;
2121

2222
@property (nonatomic, copy) RCTDirectEventBlock onShow;

React/Views/RCTModalHostView.m

+13-2
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ - (void)removeReactSubview:(UIView *)subview
8282
- (void)dismissModalViewController
8383
{
8484
if (_isPresented) {
85-
[_modalViewController dismissViewControllerAnimated:self.animated completion:nil];
85+
[_modalViewController dismissViewControllerAnimated:[self hasAnimationType] completion:nil];
8686
_isPresented = NO;
8787
}
8888
}
@@ -93,7 +93,13 @@ - (void)didMoveToWindow
9393

9494
if (!_isPresented && self.window) {
9595
RCTAssert(self.reactViewController, @"Can't present modal view controller without a presenting view controller");
96-
[self.reactViewController presentViewController:_modalViewController animated:self.animated completion:^{
96+
97+
if ([self.animationType isEqualToString:@"fade"]) {
98+
_modalViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
99+
} else if ([self.animationType isEqualToString:@"slide"]) {
100+
_modalViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
101+
}
102+
[self.reactViewController presentViewController:_modalViewController animated:[self hasAnimationType] completion:^{
97103
if (_onShow) {
98104
_onShow(nil);
99105
}
@@ -123,6 +129,11 @@ - (BOOL)isTransparent
123129
return _modalViewController.modalPresentationStyle == UIModalPresentationCustom;
124130
}
125131

132+
- (BOOL)hasAnimationType
133+
{
134+
return ![self.animationType isEqualToString:@"none"];
135+
}
136+
126137
- (void)setTransparent:(BOOL)transparent
127138
{
128139
_modalViewController.modalPresentationStyle = transparent ? UIModalPresentationCustom : UIModalPresentationFullScreen;

React/Views/RCTModalHostViewManager.m

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ - (void)invalidate
6262
[_hostViews removeAllObjects];
6363
}
6464

65-
RCT_EXPORT_VIEW_PROPERTY(animated, BOOL)
65+
RCT_EXPORT_VIEW_PROPERTY(animationType, NSString)
6666
RCT_EXPORT_VIEW_PROPERTY(transparent, BOOL)
6767
RCT_EXPORT_VIEW_PROPERTY(onShow, RCTDirectEventBlock)
6868

ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ public void onDropViewInstance(ReactModalHostView view) {
5555
view.dismiss();
5656
}
5757

58-
@ReactProp(name = "animated")
59-
public void setAnimated(ReactModalHostView view, boolean animated) {
60-
view.setAnimated(animated);
58+
@ReactProp(name = "animationType")
59+
public void setAnimationType(ReactModalHostView view, String animationType) {
60+
view.setAnimationType(animationType);
6161
}
6262

6363
@ReactProp(name = "transparent")

ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java

+7-5
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public interface OnRequestCloseListener {
5656
private DialogRootViewGroup mHostView;
5757
private @Nullable Dialog mDialog;
5858
private boolean mTransparent;
59-
private boolean mAnimated;
59+
private String mAnimationType;
6060
// Set this flag to true if changing a particular property on the view requires a new Dialog to
6161
// be created. For instance, animation does since it affects Dialog creation through the theme
6262
// but transparency does not since we can access the window to update the property.
@@ -131,8 +131,8 @@ protected void setTransparent(boolean transparent) {
131131
mTransparent = transparent;
132132
}
133133

134-
protected void setAnimated(boolean animated) {
135-
mAnimated = animated;
134+
protected void setAnimationType(String animationType) {
135+
mAnimationType = animationType;
136136
mPropertyRequiresNewDialog = true;
137137
}
138138

@@ -162,8 +162,10 @@ protected void showOrUpdate() {
162162
// Reset the flag since we are going to create a new dialog
163163
mPropertyRequiresNewDialog = false;
164164
int theme = R.style.Theme_FullScreenDialog;
165-
if (mAnimated) {
166-
theme = R.style.Theme_FullScreenDialogAnimated;
165+
if (mAnimationType.equals("fade")) {
166+
theme = R.style.Theme_FullScreenDialogAnimatedFade;
167+
} else if (mAnimationType.equals("slide")) {
168+
theme = R.style.Theme_FullScreenDialogAnimatedSlide;
167169
}
168170
mDialog = new Dialog(getContext(), theme);
169171

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:duration="@android:integer/config_shortAnimTime"
4+
android:interpolator="@android:anim/accelerate_interpolator"
5+
android:fromAlpha="0.0"
6+
android:toAlpha="1.0"
7+
/>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:duration="@android:integer/config_shortAnimTime"
4+
android:interpolator="@android:anim/accelerate_interpolator"
5+
android:fromAlpha="1.0"
6+
android:toAlpha="0.0"
7+
/>

ReactAndroid/src/main/res/views/modal/values/themes.xml

+14-3
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,24 @@
88
<item name="android:windowBackground">@android:color/transparent</item>
99
</style>
1010

11-
<style name="Theme.FullScreenDialogAnimated" parent="Theme.FullScreenDialog">
12-
<item name="android:windowAnimationStyle">@style/DialogAnimation</item>
11+
<style name="Theme.FullScreenDialogAnimatedSlide" parent="Theme.FullScreenDialog">
12+
<item name="android:windowAnimationStyle">@style/DialogAnimationSlide</item>
1313
</style>
1414

15-
<style name="DialogAnimation">
15+
<style name="Theme.FullScreenDialogAnimatedFade" parent="Theme.FullScreenDialog">
16+
<item name="android:windowAnimationStyle">@style/DialogAnimationFade</item>
17+
</style>
18+
19+
<style name="DialogAnimationSlide">
1620
<item name="android:windowEnterAnimation">@anim/slide_up</item>
1721
<item name="android:windowExitAnimation">@anim/slide_down</item>
1822
</style>
1923

24+
<style name="DialogAnimationFade">
25+
<item name="android:windowEnterAnimation">@anim/fade_in</item>
26+
<item name="android:windowExitAnimation">@anim/fade_out</item>
27+
</style>
28+
29+
30+
2031
</resources>

0 commit comments

Comments
 (0)