Support inverted gesture in modal

This commit is contained in:
Brent Vatne 2018-10-17 13:11:38 -07:00
parent d5be6307f2
commit 4f4b8e4d41
2 changed files with 62 additions and 26 deletions

View File

@ -22,6 +22,11 @@ class ListScreen extends React.Component {
} }
class DetailsScreen extends React.Component { class DetailsScreen extends React.Component {
static navigationOptions = {
// Uncomment below to test inverted modal gesture
// gestureDirection: 'inverted',
};
render() { render() {
return ( return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>

View File

@ -321,25 +321,26 @@ class StackViewLayout extends React.Component {
_gestureActivationCriteria = () => { _gestureActivationCriteria = () => {
let { layout } = this.props.transitionProps; let { layout } = this.props.transitionProps;
let gestureResponseDistance = this._getGestureResponseDistance(); let gestureResponseDistance = this._getGestureResponseDistance();
let isMotionInverted = this._isMotionInverted();
if (this._isMotionVertical()) { if (this._isMotionVertical()) {
let height = layout.height.__getValue(); let height = layout.height.__getValue();
return { return {
maxDeltaX: 15, maxDeltaX: 15,
minOffsetY: 5, minOffsetY: isMotionInverted ? -5 : 5,
hitSlop: { bottom: -height + gestureResponseDistance }, hitSlop: isMotionInverted
? { top: -height + GESTURE_RESPONSE_DISTANCE_VERTICAL }
: { bottom: -height + GESTURE_RESPONSE_DISTANCE_VERTICAL },
}; };
} else { } else {
let width = layout.width.__getValue(); let width = layout.width.__getValue();
let hitSlop = -width + gestureResponseDistance; let hitSlop = -width + gestureResponseDistance;
return { return {
minOffsetX: this._isMotionInverted() ? -5 : 5, minOffsetX: isMotionInverted ? -5 : 5,
maxDeltaY: 20, maxDeltaY: 20,
hitSlop: this._isMotionInverted() hitSlop: isMotionInverted ? { left: hitSlop } : { right: hitSlop },
? { left: hitSlop }
: { right: hitSlop },
}; };
} }
}; };
@ -370,9 +371,13 @@ class StackViewLayout extends React.Component {
const { options } = scene.descriptor; const { options } = scene.descriptor;
const { gestureDirection } = options; const { gestureDirection } = options;
return typeof gestureDirection === 'string' if (this._isModal()) {
? gestureDirection === 'inverted' return gestureDirection === 'inverted';
: I18nManager.isRTL; } else {
return typeof gestureDirection === 'string'
? gestureDirection === 'inverted'
: I18nManager.isRTL;
}
}; };
_handleHorizontalPan = nativeEvent => { _handleHorizontalPan = nativeEvent => {
@ -407,7 +412,11 @@ class StackViewLayout extends React.Component {
// TODO: remove this __getValue! // TODO: remove this __getValue!
let distance = layout.height.__getValue(); let distance = layout.height.__getValue();
let value = index - nativeEvent.translationY / distance;
let translationY = this._isMotionInverted()
? -1 * nativeEvent.translationY
: nativeEvent.translationY;
let value = index - translationY / distance;
return clamp(index - 1, value, index); return clamp(index - 1, value, index);
}; };
@ -467,22 +476,38 @@ class StackViewLayout extends React.Component {
_handleActivateGestureVertical = () => { _handleActivateGestureVertical = () => {
let { index } = this.props.transitionProps.navigation.state; let { index } = this.props.transitionProps.navigation.state;
this.setState({ if (this._isMotionInverted()) {
gesturePosition: Animated.add( this.setState({
index, gesturePosition: Animated.add(
Animated.multiply( index,
-1,
Animated.divide( Animated.divide(
this.gestureY, this.gestureY,
this.props.transitionProps.layout.height this.props.transitionProps.layout.height
) )
) ).interpolate({
).interpolate({ inputRange: [index - 1, index],
inputRange: [index - 1, index], outputRange: [index - 1, index],
outputRange: [index - 1, index], extrapolate: 'clamp',
extrapolate: 'clamp', }),
}), });
}); } else {
this.setState({
gesturePosition: Animated.add(
index,
Animated.multiply(
-1,
Animated.divide(
this.gestureY,
this.props.transitionProps.layout.height
)
)
).interpolate({
inputRange: [index - 1, index],
outputRange: [index - 1, index],
extrapolate: 'clamp',
}),
});
}
}; };
_handleReleaseHorizontal = nativeEvent => { _handleReleaseHorizontal = nativeEvent => {
@ -547,12 +572,18 @@ class StackViewLayout extends React.Component {
// Calculate animate duration according to gesture speed and moved distance // Calculate animate duration according to gesture speed and moved distance
const distance = layout.height.__getValue(); const distance = layout.height.__getValue();
const movedDistance = nativeEvent.translationY; const isMotionInverted = this._isMotionInverted();
const gestureVelocity = nativeEvent.velocityY; const movementDirection = isMotionInverted ? -1 : 1;
const movedDistance = movementDirection * nativeEvent.translationY;
const gestureVelocity = movementDirection * nativeEvent.velocityY;
const defaultVelocity = distance / ANIMATION_DURATION; const defaultVelocity = distance / ANIMATION_DURATION;
const velocity = Math.max(Math.abs(gestureVelocity), defaultVelocity); const velocity = Math.max(Math.abs(gestureVelocity), defaultVelocity);
const resetDuration = movedDistance / velocity; const resetDuration = isMotionInverted
const goBackDuration = (distance - movedDistance) / velocity; ? (distance - movedDistance) / velocity
: movedDistance / velocity;
const goBackDuration = isMotionInverted
? movedDistance / velocity
: (distance - movedDistance) / velocity;
let value = this._computeVerticalGestureValue(nativeEvent); let value = this._computeVerticalGestureValue(nativeEvent);
position.setValue(value); position.setValue(value);