Enable configuration of gesture direction (#3077)

* Enable configuration of gesture direction

* Fix documentation and code style

* Invert behaviour of I18nManager.isRTL instead of overriding
This commit is contained in:
Axel Eirola
2017-12-18 23:25:16 +02:00
parent 395dee489a
commit 78c6d92cad
3 changed files with 22 additions and 7 deletions

View File

@@ -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:

View File

@@ -324,6 +324,7 @@ export type NavigationStackScreenOptions = NavigationScreenOptions & {
headerStyle?: ViewStyleProp,
gesturesEnabled?: boolean,
gestureResponseDistance?: { vertical?: number, horizontal?: number },
gestureDirection?: 'default' | 'inverted',
};
export type NavigationStackRouterConfig = {

View File

@@ -240,6 +240,8 @@ class CardStack extends React.Component<Props> {
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<Props> {
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<Props> {
? 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<Props> {
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<Props> {
},
});
const { options } = this._getScreenDetails(scene);
const gesturesEnabled =
typeof options.gesturesEnabled === 'boolean'
? options.gesturesEnabled