Skip to content

Commit aa5c54f

Browse files
authored
Fix/dialog animation (#891)
* use View internal animated prop * remove redundant state change * change easing * Animated overlay background separately * Extract the Overlay fading background into a separate component * fix lint issue * remove unused animationStyle * Add hook dependencies according to the lint recommendations * Remove redundant isAnimating flag
1 parent e73e91a commit aa5c54f

File tree

5 files changed

+77
-37
lines changed

5 files changed

+77
-37
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/// <reference types="react" />
2+
interface Props {
3+
dialogVisibility: boolean;
4+
modalVisibility: boolean;
5+
overlayBackgroundColor: string;
6+
}
7+
declare const _default: ({ dialogVisibility, modalVisibility, overlayBackgroundColor }: Props) => JSX.Element;
8+
export default _default;

src/components/dialog/DialogDismissibleView.js

Lines changed: 10 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ class DialogDismissibleView extends PureComponent {
4242
this.setInitialValues();
4343
this.state = {
4444
visible: props.visible,
45-
hide: false,
46-
isAnimating: false
45+
hide: false
4746
};
4847
}
4948

@@ -54,22 +53,12 @@ class DialogDismissibleView extends PureComponent {
5453
this.width = Constants.screenWidth;
5554
this.height = Constants.screenHeight;
5655
this.hiddenLocation = this.getHiddenLocation(0, 0);
57-
this.animationStyle = {
58-
transform: [
59-
{
60-
translateX: this.hiddenLocation.left
61-
},
62-
{
63-
translateY: this.hiddenLocation.top
64-
}
65-
]
66-
};
6756
}
6857

6958
componentDidUpdate(prevProps) {
7059
const {isPanning, dragDeltas, swipeDirections} = this.props.context; // eslint-disable-line
7160
const {dragDeltas: prevDragDeltas, swipeDirections: prevSwipeDirections} = prevProps.context; // eslint-disable-line
72-
const {hide, isAnimating} = this.state;
61+
const {hide} = this.state;
7362

7463
if (
7564
isPanning &&
@@ -87,7 +76,7 @@ class DialogDismissibleView extends PureComponent {
8776
this.onSwipe(swipeDirections);
8877
}
8978

90-
if (hide && !isAnimating) {
79+
if (hide) {
9180
this.hide();
9281
}
9382
}
@@ -126,10 +115,6 @@ class DialogDismissibleView extends PureComponent {
126115
this.swipe = swipeDirections;
127116
};
128117

129-
onAnimationEnd = () => {
130-
this.setState({isAnimating: false});
131-
};
132-
133118
getHiddenLocation = (left, top) => {
134119
const {direction} = this.props;
135120
const topInset = Constants.isIphoneX ? Constants.getSafeAreaInsets().top : Constants.isIOS ? 20 : 0;
@@ -156,14 +141,12 @@ class DialogDismissibleView extends PureComponent {
156141
};
157142

158143
animateTo = (toValue, animationEndCallback) => {
159-
const animation = Animated.timing(this.animatedValue, {
144+
Animated.timing(this.animatedValue, {
160145
toValue,
161-
duration: 400,
162-
easing: Easing.bezier(0.65, 0, 0.35, 1),
146+
duration: 300,
147+
easing: Easing.bezier(0.2, 0, 0.35, 1),
163148
useNativeDriver: true
164-
});
165-
166-
this.setState({isAnimating: true}, () => animation.start(animationEndCallback));
149+
}).start(animationEndCallback);
167150
};
168151

169152
getAnimationStyle = () => {
@@ -194,8 +177,7 @@ class DialogDismissibleView extends PureComponent {
194177
this.thresholdY = this.height / 2;
195178
this.ref.measureInWindow((x, y) => {
196179
this.hiddenLocation = this.getHiddenLocation(x, y);
197-
this.animationStyle = this.getAnimationStyle();
198-
this.animateTo(1, this.onAnimationEnd);
180+
this.animateTo(1);
199181
});
200182
};
201183

@@ -210,7 +192,7 @@ class DialogDismissibleView extends PureComponent {
210192
? 1 + left / this.hiddenLocation.left
211193
: 1 + top / this.hiddenLocation.top;
212194

213-
this.animateTo(toValue, this.onAnimationEnd);
195+
this.animateTo(toValue);
214196
};
215197

216198
onPanLocationChanged = ({left, top}) => {
@@ -241,7 +223,7 @@ class DialogDismissibleView extends PureComponent {
241223
<View ref={r => (this.ref = r)} style={containerStyle} onLayout={this.onLayout}>
242224
<PanResponderView
243225
// !visible && styles.hidden is done to fix a bug is iOS
244-
style={[style, this.animationStyle, !visible && styles.hidden]}
226+
style={[style, this.getAnimationStyle(), !visible && styles.hidden]}
245227
isAnimated
246228
onPanLocationChanged={this.onPanLocationChanged}
247229
>
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import React, {useRef, useEffect, useCallback, useMemo} from 'react';
2+
import View from '../view';
3+
import {Animated} from 'react-native';
4+
5+
interface Props {
6+
dialogVisibility: boolean;
7+
modalVisibility: boolean;
8+
overlayBackgroundColor: string;
9+
}
10+
11+
export default ({
12+
dialogVisibility,
13+
modalVisibility,
14+
overlayBackgroundColor
15+
}: Props) => {
16+
const fadeAnimation = useRef(new Animated.Value(0)).current;
17+
18+
const animateFading = useCallback((toValue) => {
19+
Animated.timing(fadeAnimation, {
20+
toValue,
21+
duration: 400,
22+
useNativeDriver: true
23+
}).start();
24+
}, [fadeAnimation]);
25+
26+
useEffect(() => {
27+
if (!dialogVisibility) {
28+
animateFading(0);
29+
}
30+
}, [dialogVisibility, animateFading]);
31+
32+
useEffect(() => {
33+
if (modalVisibility) {
34+
animateFading(1);
35+
}
36+
}, [modalVisibility, animateFading]);
37+
38+
const style = useMemo(() => {
39+
return {
40+
opacity: fadeAnimation,
41+
backgroundColor: overlayBackgroundColor
42+
};
43+
}, [overlayBackgroundColor, fadeAnimation]);
44+
45+
return <View absF animated style={style} pointerEvents="none"/>;
46+
};

src/components/dialog/index.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import Modal from '../modal';
1010
import View from '../view';
1111
import PanListenerView from '../panningViews/panListenerView';
1212
import DialogDismissibleView from './DialogDismissibleView';
13+
import OverlayFadingBackground from './OverlayFadingBackground';
1314
import PanningProvider from '../panningViews/panningProvider';
1415

1516
// TODO: KNOWN ISSUES
@@ -155,7 +156,7 @@ class Dialog extends BaseComponent {
155156
}
156157
});
157158
};
158-
159+
159160
onModalDismissed = () => {
160161
_.invoke(this.props, 'onDialogDismissed', this.props);
161162
_.invoke(this.props, 'onModalDismissed', this.props);
@@ -199,7 +200,8 @@ class Dialog extends BaseComponent {
199200

200201
// TODO: renderOverlay {_.invoke(this.getThemeProps(), 'renderOverlay')}
201202
renderDialogContainer = () => {
202-
const {useSafeArea, bottom} = this.getThemeProps();
203+
const {modalVisibility, dialogVisibility} = this.state;
204+
const {useSafeArea, bottom, overlayBackgroundColor} = this.getThemeProps();
203205
const addBottomSafeArea = Constants.isIphoneX && (useSafeArea && bottom);
204206
const bottomInsets = Constants.getSafeAreaInsets().bottom - 8; // TODO: should this be here or in the input style?
205207

@@ -209,6 +211,11 @@ class Dialog extends BaseComponent {
209211
style={[this.styles.centerHorizontal, this.styles.alignments, this.styles.container]}
210212
pointerEvents="box-none"
211213
>
214+
<OverlayFadingBackground
215+
modalVisibility={modalVisibility}
216+
dialogVisibility={dialogVisibility}
217+
overlayBackgroundColor={overlayBackgroundColor}
218+
/>
212219
{this.renderDialogView()}
213220
{addBottomSafeArea && <View style={{marginTop: bottomInsets}}/>}
214221
</View>
@@ -217,17 +224,16 @@ class Dialog extends BaseComponent {
217224

218225
render = () => {
219226
const {orientationKey, modalVisibility} = this.state;
220-
const {overlayBackgroundColor, supportedOrientations, accessibilityLabel} = this.getThemeProps();
227+
const {supportedOrientations, accessibilityLabel} = this.getThemeProps();
221228

222229
return (
223230
<Modal
224231
key={orientationKey}
225232
transparent
226233
visible={modalVisibility}
227-
animationType={'fade'}
234+
animationType={'none'}
228235
onBackgroundPress={this.hideDialogView}
229236
onRequestClose={this.hideDialogView}
230-
overlayBackgroundColor={overlayBackgroundColor}
231237
onDismiss={this.onModalDismissed}
232238
supportedOrientations={supportedOrientations}
233239
accessibilityLabel={accessibilityLabel}

src/components/panningViews/panResponderView.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import _ from 'lodash';
22
import PropTypes from 'prop-types';
33
import React, {PureComponent} from 'react';
4-
import {Animated} from 'react-native';
54
import View from '../view';
65
import asPanViewConsumer from './asPanViewConsumer';
76

@@ -89,12 +88,11 @@ class PanResponderView extends PureComponent {
8988

9089
render() {
9190
const {isAnimated, ...others} = this.props;
92-
const Container = isAnimated ? Animated.View : View;
9391

9492
return (
95-
<Container ref={this.ref} pointerEvents={'box-none'} {...others}>
93+
<View animated={isAnimated} ref={this.ref} pointerEvents={'box-none'} {...others}>
9694
{this.props.children}
97-
</Container>
95+
</View>
9896
);
9997
}
10098
}

0 commit comments

Comments
 (0)