mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-02-12 09:21:09 +08:00
stop using Animated.spring (#1500)
* stop using Animated.spring * use layout instead of window.size
This commit is contained in:
73
packages/react-navigation/src/views/CardStack.js
vendored
73
packages/react-navigation/src/views/CardStack.js
vendored
@@ -10,6 +10,7 @@ import {
|
||||
Platform,
|
||||
View,
|
||||
I18nManager,
|
||||
Easing,
|
||||
} from 'react-native';
|
||||
|
||||
import Card from './Card';
|
||||
@@ -63,9 +64,11 @@ type Props = {
|
||||
};
|
||||
|
||||
/**
|
||||
* The duration of the card animation in milliseconds.
|
||||
* The max duration of the card animation in milliseconds after released gesture.
|
||||
* The actual duration should be always less then that because the rest distance
|
||||
* is always less then the full distance of the layout.
|
||||
*/
|
||||
const ANIMATION_DURATION = 200;
|
||||
const ANIMATION_DURATION = 250;
|
||||
|
||||
/**
|
||||
* The gesture distance threshold to trigger the back behavior. For instance,
|
||||
@@ -94,14 +97,6 @@ const animatedSubscribeValue = (animatedValue: Animated.Value) => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The ratio between the gesture velocity and the animation velocity. This allows
|
||||
* the velocity of a swipe release to carry on into the new animation.
|
||||
*
|
||||
* TODO: Understand and compute this ratio rather than using an approximation
|
||||
*/
|
||||
const GESTURE_ANIMATED_VELOCITY_RATIO = -4;
|
||||
|
||||
class CardStack extends Component {
|
||||
/**
|
||||
* Used to identify the starting point of the position when the gesture starts, such that it can
|
||||
@@ -199,17 +194,16 @@ class CardStack extends Component {
|
||||
animatedSubscribeValue(props.position);
|
||||
}
|
||||
|
||||
_reset(resetToIndex: number, velocity: number): void {
|
||||
Animated.spring(this.props.position, {
|
||||
_reset(resetToIndex: number, duration: number): void {
|
||||
Animated.timing(this.props.position, {
|
||||
toValue: resetToIndex,
|
||||
duration: ANIMATION_DURATION,
|
||||
duration,
|
||||
easing: Easing.inOut(Easing.ease),
|
||||
useNativeDriver: this.props.position.__isNative,
|
||||
velocity: velocity * GESTURE_ANIMATED_VELOCITY_RATIO,
|
||||
bounciness: 0,
|
||||
}).start();
|
||||
}
|
||||
|
||||
_goBack(backFromIndex: number, velocity: number) {
|
||||
_goBack(backFromIndex: number, duration: number) {
|
||||
const { navigation, position, scenes } = this.props;
|
||||
const toValue = Math.max(backFromIndex - 1, 0);
|
||||
|
||||
@@ -217,12 +211,11 @@ class CardStack extends Component {
|
||||
// dispatched at the end of the transition.
|
||||
this._immediateIndex = toValue;
|
||||
|
||||
Animated.spring(position, {
|
||||
Animated.timing(position, {
|
||||
toValue,
|
||||
duration: ANIMATION_DURATION,
|
||||
duration,
|
||||
easing: Easing.inOut(Easing.ease),
|
||||
useNativeDriver: position.__isNative,
|
||||
velocity: velocity * GESTURE_ANIMATED_VELOCITY_RATIO,
|
||||
bounciness: 0,
|
||||
}).start(() => {
|
||||
this._immediateIndex = null;
|
||||
const backFromScene = scenes.find((s: *) => s.index === toValue + 1);
|
||||
@@ -240,8 +233,10 @@ class CardStack extends Component {
|
||||
if (headerMode === 'float') {
|
||||
floatingHeader = this._renderHeader(this.props.scene, headerMode);
|
||||
}
|
||||
const { navigation, position, scene, mode, scenes } = this.props;
|
||||
const { navigation, position, layout, scene, scenes, mode } = this.props;
|
||||
const { index } = navigation.state;
|
||||
const isVertical = mode === 'modal';
|
||||
|
||||
const responder = PanResponder.create({
|
||||
onPanResponderTerminate: () => {
|
||||
this._isResponding = false;
|
||||
@@ -257,11 +252,9 @@ class CardStack extends Component {
|
||||
event: { nativeEvent: { pageY: number, pageX: number } },
|
||||
gesture: any,
|
||||
) => {
|
||||
const layout = this.props.layout;
|
||||
if (index !== scene.index) {
|
||||
return false;
|
||||
}
|
||||
const isVertical = mode === 'modal';
|
||||
const immediateIndex = this._immediateIndex == null
|
||||
? index
|
||||
: this._immediateIndex;
|
||||
@@ -297,16 +290,14 @@ class CardStack extends Component {
|
||||
},
|
||||
onPanResponderMove: (event: any, gesture: any) => {
|
||||
// Handle the moving touches for our granted responder
|
||||
const layout = this.props.layout;
|
||||
const isVertical = mode === 'modal';
|
||||
const startValue = this._gestureStartValue;
|
||||
const axis = isVertical ? 'dy' : 'dx';
|
||||
const distance = isVertical
|
||||
const axisDistance = isVertical
|
||||
? layout.height.__getValue()
|
||||
: layout.width.__getValue();
|
||||
const currentValue = I18nManager.isRTL && axis === 'dx'
|
||||
? startValue + gesture[axis] / distance
|
||||
: startValue - gesture[axis] / distance;
|
||||
? startValue + gesture[axis] / axisDistance
|
||||
: startValue - gesture[axis] / axisDistance;
|
||||
const value = clamp(index - 1, currentValue, index);
|
||||
position.setValue(value);
|
||||
},
|
||||
@@ -319,31 +310,41 @@ class CardStack extends Component {
|
||||
return;
|
||||
}
|
||||
this._isResponding = false;
|
||||
const isVertical = mode === 'modal';
|
||||
const velocity = gesture[isVertical ? 'vy' : 'vx'];
|
||||
|
||||
const immediateIndex = this._immediateIndex == null
|
||||
? index
|
||||
: this._immediateIndex;
|
||||
|
||||
// Calculate animate duration according to gesture speed and moved distance
|
||||
const axisDistance = isVertical
|
||||
? layout.height.__getValue()
|
||||
: layout.width.__getValue();
|
||||
const movedDistance = gesture[isVertical ? 'moveY' : 'moveX'];
|
||||
const defaultVelocity = axisDistance / ANIMATION_DURATION;
|
||||
const gestureVelocity = gesture[isVertical ? 'vy' : 'vx'];
|
||||
const velocity = Math.max(gestureVelocity, defaultVelocity);
|
||||
const resetDuration = movedDistance / velocity;
|
||||
const goBackDuration = (axisDistance - movedDistance) / velocity;
|
||||
|
||||
// To asyncronously get the current animated value, we need to run stopAnimation:
|
||||
position.stopAnimation((value: number) => {
|
||||
// If the speed of the gesture release is significant, use that as the indication
|
||||
// of intent
|
||||
if (velocity < -0.5) {
|
||||
this._reset(immediateIndex, velocity);
|
||||
if (gestureVelocity < -0.5) {
|
||||
this._reset(immediateIndex, resetDuration);
|
||||
return;
|
||||
}
|
||||
if (velocity > 0.5) {
|
||||
this._goBack(immediateIndex, velocity);
|
||||
if (gestureVelocity > 0.5) {
|
||||
this._goBack(immediateIndex, goBackDuration);
|
||||
return;
|
||||
}
|
||||
|
||||
// Then filter based on the distance the screen was moved. Over a third of the way swiped,
|
||||
// and the back will happen.
|
||||
if (value <= index - POSITION_THRESHOLD) {
|
||||
this._goBack(immediateIndex, velocity);
|
||||
this._goBack(immediateIndex, goBackDuration);
|
||||
} else {
|
||||
this._reset(immediateIndex, velocity);
|
||||
this._reset(immediateIndex, resetDuration);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@@ -12,11 +12,9 @@ import CardStackStyleInterpolator from './CardStackStyleInterpolator';
|
||||
|
||||
// Used for all animations unless overriden
|
||||
const DefaultTransitionSpec = ({
|
||||
// The following options are meant to mimic the nav animations of iOS 10
|
||||
duration: 250,
|
||||
timing: Animated.spring,
|
||||
bounciness: 0,
|
||||
speed: 9,
|
||||
easing: Easing.inOut(Easing.ease),
|
||||
timing: Animated.timing,
|
||||
}: NavigationTransitionSpec);
|
||||
|
||||
// Standard iOS navigation transition
|
||||
|
||||
Reference in New Issue
Block a user