diff --git a/docs/api/navigators/StackNavigator.md b/docs/api/navigators/StackNavigator.md index cb4ca922..29abce0f 100644 --- a/docs/api/navigators/StackNavigator.md +++ b/docs/api/navigators/StackNavigator.md @@ -158,6 +158,10 @@ Object to override the distance of touch start from the edge of the screen to re - `horizontal` - *number* - Distance for horizontal direction. Defaults to 25. - `vertical` - *number* - Distance for vertical direction. Defaults to 135. +#### `gestureDirection` + +String to override the direction for dismiss gesture. `default` for normal behaviour or `inverted` for right-to-left swipes. + ### Navigator Props The navigator component created by `StackNavigator(...)` takes the following props: diff --git a/src/TypeDefinition.js b/src/TypeDefinition.js index e343860c..9602bca3 100644 --- a/src/TypeDefinition.js +++ b/src/TypeDefinition.js @@ -324,6 +324,7 @@ export type NavigationStackScreenOptions = NavigationScreenOptions & { headerStyle?: ViewStyleProp, gesturesEnabled?: boolean, gestureResponseDistance?: { vertical?: number, horizontal?: number }, + gestureDirection?: 'default' | 'inverted', }; export type NavigationStackRouterConfig = { diff --git a/src/views/CardStack/CardStack.js b/src/views/CardStack/CardStack.js index 942713bd..d11aa712 100644 --- a/src/views/CardStack/CardStack.js +++ b/src/views/CardStack/CardStack.js @@ -240,6 +240,8 @@ class CardStack extends React.Component { const { navigation, position, layout, scene, scenes, mode } = this.props; const { index } = navigation.state; const isVertical = mode === 'modal'; + const { options } = this._getScreenDetails(scene); + const gestureDirectionInverted = options.gestureDirection === 'inverted'; const responder = PanResponder.create({ onPanResponderTerminate: () => { @@ -270,7 +272,9 @@ class CardStack extends React.Component { const axisHasBeenMeasured = !!axisLength; // Measure the distance from the touch to the edge of the screen - const screenEdgeDistance = currentDragPosition - currentDragDistance; + const screenEdgeDistance = gestureDirectionInverted + ? axisLength - (currentDragPosition - currentDragDistance) + : currentDragPosition - currentDragDistance; // Compare to the gesture distance relavant to card or modal const { gestureResponseDistance: userGestureResponseDistance = {}, @@ -302,7 +306,7 @@ class CardStack extends React.Component { ? layout.height.__getValue() : layout.width.__getValue(); const currentValue = - I18nManager.isRTL && axis === 'dx' + (I18nManager.isRTL && axis === 'dx') !== gestureDirectionInverted ? startValue + gesture[axis] / axisDistance : startValue - gesture[axis] / axisDistance; const value = clamp(index - 1, currentValue, index); @@ -325,12 +329,19 @@ class CardStack extends React.Component { const axisDistance = isVertical ? layout.height.__getValue() : layout.width.__getValue(); - const movedDistance = gesture[isVertical ? 'dy' : 'dx']; - const gestureVelocity = gesture[isVertical ? 'vy' : 'vx']; + const movementDirection = gestureDirectionInverted ? -1 : 1; + const movedDistance = + movementDirection * gesture[isVertical ? 'dy' : 'dx']; + const gestureVelocity = + movementDirection * gesture[isVertical ? 'vy' : 'vx']; const defaultVelocity = axisDistance / ANIMATION_DURATION; const velocity = Math.max(Math.abs(gestureVelocity), defaultVelocity); - const resetDuration = movedDistance / velocity; - const goBackDuration = (axisDistance - movedDistance) / velocity; + const resetDuration = gestureDirectionInverted + ? (axisDistance - movedDistance) / velocity + : movedDistance / velocity; + const goBackDuration = gestureDirectionInverted + ? movedDistance / velocity + : (axisDistance - movedDistance) / velocity; // To asyncronously get the current animated value, we need to run stopAnimation: position.stopAnimation((value: number) => { @@ -356,7 +367,6 @@ class CardStack extends React.Component { }, }); - const { options } = this._getScreenDetails(scene); const gesturesEnabled = typeof options.gesturesEnabled === 'boolean' ? options.gesturesEnabled