Skip to content
This repository was archived by the owner on Feb 25, 2020. It is now read-only.

Commit 95fe56e

Browse files
wojtus7osdnk
authored andcommitted
feat: add 'vertical-inverted' as gesture direction (#184)
As for now there is no way to dismiss modal by moving up, only swiping down is available. https://streamable.com/s/ogjyq/gqugbc
1 parent a5f7517 commit 95fe56e

3 files changed

Lines changed: 116 additions & 12 deletions

File tree

example/src/ModalStack.js

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,79 @@
11
import * as React from 'react';
2-
import { Button, View, Text } from 'react-native';
3-
import { createStackNavigator } from 'react-navigation-stack';
2+
import { Button, View, Text, Dimensions, Switch } from 'react-native';
3+
import {
4+
createStackNavigator,
5+
CardStyleInterpolators,
6+
} from 'react-navigation-stack';
7+
import Animated from 'react-native-reanimated';
8+
9+
const { interpolate } = Animated;
10+
11+
const gestureResponseDistance = {
12+
vertical: Dimensions.get('window').height,
13+
};
14+
15+
function forVerticalInvertedIOS({
16+
progress: { current },
17+
layouts: { screen },
18+
}) {
19+
const translateY = interpolate(current, {
20+
inputRange: [0, 1],
21+
outputRange: [-screen.height, 0],
22+
});
23+
24+
return {
25+
cardStyle: {
26+
transform: [
27+
// Translation for the animation of the current card
28+
{ translateY },
29+
],
30+
},
31+
};
32+
}
33+
34+
class Modal extends React.Component {
35+
static navigationOptions = ({ navigation }) => {
36+
return {
37+
title: 'Modal',
38+
cardStyleInterpolator:
39+
navigation.getParam('gestureDirection', 'vertical') ===
40+
'vertical-inverted'
41+
? forVerticalInvertedIOS
42+
: CardStyleInterpolators.forVerticalIOS,
43+
gestureDirection: navigation.getParam('gestureDirection', 'vertical'),
44+
cardTransparent: true,
45+
gestureResponseDistance,
46+
};
47+
};
48+
49+
render() {
50+
return (
51+
<View
52+
style={{
53+
backgroundColor: 'white',
54+
paddingVertical: 20,
55+
paddingHorizontal: 20,
56+
height: Dimensions.get('screen').height,
57+
shadowColor: '#000',
58+
shadowOffset: { width: 0, height: 10 },
59+
shadowOpacity: 0.2,
60+
shadowRadius: 4,
61+
}}
62+
/>
63+
);
64+
}
65+
}
466

567
class ListScreen extends React.Component {
668
static navigationOptions = {
769
title: 'My Modal',
870
};
971

72+
state = { isInverted: false };
73+
74+
onSwitch = () =>
75+
this.setState(prevState => ({ isInverted: !prevState.isInverted }));
76+
1077
render() {
1178
return (
1279
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
@@ -20,6 +87,22 @@ class ListScreen extends React.Component {
2087
title="Go back to all examples"
2188
onPress={() => this.props.navigation.navigate('Home')}
2289
/>
90+
<Text>Invert modal gesture direction:</Text>
91+
<Switch
92+
style={{ margin: 10 }}
93+
onValueChange={this.onSwitch}
94+
value={this.state.isInverted}
95+
/>
96+
<Button
97+
title="Show Modal"
98+
onPress={() =>
99+
this.props.navigation.push('Modal', {
100+
gestureDirection: this.state.isInverted
101+
? 'vertical-inverted'
102+
: 'vertical',
103+
})
104+
}
105+
/>
23106
</View>
24107
);
25108
}
@@ -60,6 +143,7 @@ export default createStackNavigator(
60143
{
61144
List: ListScreen,
62145
Details: DetailsScreen,
146+
Modal: Modal,
63147
},
64148
{
65149
initialRouteName: 'List',

src/types.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export type NavigationProp<RouteName = string, Params = object> = {
4747

4848
export type Layout = { width: number; height: number };
4949

50-
export type GestureDirection = 'horizontal' | 'vertical';
50+
export type GestureDirection = 'horizontal' | 'vertical' | 'vertical-inverted';
5151

5252
export type HeaderMode = 'float' | 'screen' | 'none';
5353

src/views/Stack/Card.tsx

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ type Props = ViewProps & {
2626
next?: Animated.Node<number>;
2727
current: Animated.Value<number>;
2828
layout: Layout;
29-
gestureDirection: 'horizontal' | 'vertical';
29+
gestureDirection: 'horizontal' | 'vertical' | 'vertical-inverted';
3030
onOpen: (isFinished: boolean) => void;
3131
onClose: (isFinished: boolean) => void;
3232
onTransitionStart?: (props: { closing: boolean }) => void;
@@ -56,6 +56,8 @@ const TRUE = 1;
5656
const FALSE = 0;
5757
const NOOP = 0;
5858
const UNSET = -1;
59+
const TOP = -1;
60+
const BOTTOM = 1;
5961

6062
const DIRECTION_VERTICAL = -1;
6163
const DIRECTION_HORIZONTAL = 1;
@@ -115,10 +117,14 @@ export default class Card extends React.Component<Props> {
115117

116118
if (gestureDirection !== prevProps.gestureDirection) {
117119
this.direction.setValue(
118-
gestureDirection === 'vertical'
120+
gestureDirection === 'vertical' ||
121+
gestureDirection === 'vertical-inverted'
119122
? DIRECTION_VERTICAL
120123
: DIRECTION_HORIZONTAL
121124
);
125+
this.verticalGestureDirection.setValue(
126+
gestureDirection === 'vertical-inverted' ? TOP : BOTTOM
127+
);
122128
}
123129

124130
if (closing !== prevProps.closing) {
@@ -129,6 +135,9 @@ export default class Card extends React.Component<Props> {
129135
private isVisible = new Value<Binary>(TRUE);
130136
private isVisibleValue: Binary = TRUE;
131137
private nextIsVisible = new Value<Binary | -1>(UNSET);
138+
private verticalGestureDirection = new Value(
139+
this.props.gestureDirection === 'vertical-inverted' ? TOP : BOTTOM
140+
);
132141

133142
private isClosing = new Value<Binary>(FALSE);
134143
private noAnimationStartedSoFar = true;
@@ -137,7 +146,8 @@ export default class Card extends React.Component<Props> {
137146
private clock = new Clock();
138147

139148
private direction = new Value(
140-
this.props.gestureDirection === 'vertical'
149+
this.props.gestureDirection === 'vertical' ||
150+
this.props.gestureDirection === 'vertical-inverted'
141151
? DIRECTION_VERTICAL
142152
: DIRECTION_HORIZONTAL
143153
);
@@ -370,9 +380,9 @@ export default class Card extends React.Component<Props> {
370380
private handleGestureEventHorizontal = Animated.event([
371381
{
372382
nativeEvent: {
373-
translationX: (x: Animated.Adaptable<number>) =>
383+
translationX: (x: Animated.Node<number>) =>
374384
set(this.gesture, multiply(x, I18nManager.isRTL ? -1 : 1)),
375-
velocityX: (x: Animated.Adaptable<number>) =>
385+
velocityX: (x: Animated.Node<number>) =>
376386
set(this.velocity, multiply(x, I18nManager.isRTL ? -1 : 1)),
377387
state: this.gestureState,
378388
},
@@ -382,8 +392,10 @@ export default class Card extends React.Component<Props> {
382392
private handleGestureEventVertical = Animated.event([
383393
{
384394
nativeEvent: {
385-
translationY: this.gesture,
386-
velocityY: this.velocity,
395+
translationY: (y: Animated.Node<number>) =>
396+
set(this.gesture, multiply(y, this.verticalGestureDirection)),
397+
velocityY: (y: Animated.Node<number>) =>
398+
set(this.velocity, multiply(y, this.verticalGestureDirection)),
387399
state: this.gestureState,
388400
},
389401
},
@@ -431,7 +443,8 @@ export default class Card extends React.Component<Props> {
431443

432444
// Doesn't make sense for a response distance of 0, so this works fine
433445
const distance =
434-
gestureDirection === 'vertical'
446+
gestureDirection === 'vertical' ||
447+
gestureDirection === 'vertical-inverted'
435448
? (gestureResponseDistance && gestureResponseDistance.vertical) ||
436449
GESTURE_RESPONSE_DISTANCE_VERTICAL
437450
: (gestureResponseDistance && gestureResponseDistance.horizontal) ||
@@ -443,6 +456,12 @@ export default class Card extends React.Component<Props> {
443456
minOffsetY: 5,
444457
hitSlop: { bottom: -layout.height + distance },
445458
};
459+
} else if (gestureDirection === 'vertical-inverted') {
460+
return {
461+
maxDeltaX: 15,
462+
minOffsetY: -5,
463+
hitSlop: { top: -layout.height + distance },
464+
};
446465
} else {
447466
const hitSlop = -layout.width + distance;
448467

@@ -497,7 +516,8 @@ export default class Card extends React.Component<Props> {
497516
);
498517

499518
const handleGestureEvent =
500-
gestureDirection === 'vertical'
519+
gestureDirection === 'vertical' ||
520+
gestureDirection === 'vertical-inverted'
501521
? this.handleGestureEventVertical
502522
: this.handleGestureEventHorizontal;
503523

0 commit comments

Comments
 (0)