Skip to content

Commit 88d72a9

Browse files
WoLewickipiaskowyk
andauthored
feat: add full screen swipe (software-mansion#1913)
## Summary This pull request introduces a new feature which adds screen "go back" transition animations based on gestures. The feature is a collaboration between three libraries: `react-native-reanimated`, `react-native-screens`, and `react-native-gesture-handler`. Implementing this feature required changes in both Reanimated and RNScreens. You can find the related pull request in the `react-native-reanimated` repository: [PR 1913](software-mansion/react-native-reanimated#5274). ## Test plan Test example from Example App --------- Co-authored-by: Krzysztof Piaskowy <krzysztof.piaskowy@swmansion.com>
1 parent e0bbf77 commit 88d72a9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1770
-108
lines changed

.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ module.exports = {
1818
'react-native-screens',
1919
'react-native-screens/native-stack',
2020
'react-native-screens/reanimated',
21+
'react-native-screens/gesture-handler',
2122
],
2223
'import/ignore': [
2324
'node_modules/react-native/index\\.js$',

Example/App.tsx

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import RNRestart from 'react-native-restart';
1515
import { ListItem, SettingsSwitch } from './src/shared';
1616

1717
import SimpleNativeStack from './src/screens/SimpleNativeStack';
18+
import SwipeBackAnimation from './src/screens/SwipeBackAnimation';
1819
import StackPresentation from './src/screens/StackPresentation';
1920
import HeaderOptions from './src/screens/HeaderOptions';
2021
import StatusBarExample from './src/screens/StatusBar';
@@ -27,6 +28,8 @@ import Events from './src/screens/Events';
2728
import Gestures from './src/screens/Gestures';
2829

2930
import { enableFreeze } from 'react-native-screens';
31+
import { GestureDetectorProvider } from 'react-native-screens/gesture-handler';
32+
import { GestureHandlerRootView } from 'react-native-gesture-handler';
3033

3134
enableFreeze();
3235

@@ -47,6 +50,11 @@ const SCREENS: Record<
4750
component: SimpleNativeStack,
4851
type: 'example',
4952
},
53+
SwipeBackAnimation: {
54+
title: 'Swipe Back Animation',
55+
component: SwipeBackAnimation,
56+
type: 'example',
57+
},
5058
StackPresentation: {
5159
title: 'Stack Presentation',
5260
component: StackPresentation,
@@ -150,26 +158,30 @@ const MainScreen = ({ navigation }: MainScreenProps): JSX.Element => (
150158
);
151159

152160
const ExampleApp = (): JSX.Element => (
153-
<NavigationContainer>
154-
<Stack.Navigator
155-
screenOptions={{
156-
direction: I18nManager.isRTL ? 'rtl' : 'ltr',
157-
}}>
158-
<Stack.Screen
159-
name="Main"
160-
options={{ title: '📱 React Native Screens Examples' }}
161-
component={MainScreen}
162-
/>
163-
{Object.keys(SCREENS).map(name => (
164-
<Stack.Screen
165-
key={name}
166-
name={name}
167-
getComponent={() => SCREENS[name].component}
168-
options={{ headerShown: false }}
169-
/>
170-
))}
171-
</Stack.Navigator>
172-
</NavigationContainer>
161+
<GestureHandlerRootView style={{ flex: 1 }}>
162+
<GestureDetectorProvider>
163+
<NavigationContainer>
164+
<Stack.Navigator
165+
screenOptions={{
166+
direction: I18nManager.isRTL ? 'rtl' : 'ltr',
167+
}}>
168+
<Stack.Screen
169+
name="Main"
170+
options={{ title: '📱 React Native Screens Examples' }}
171+
component={MainScreen}
172+
/>
173+
{Object.keys(SCREENS).map(name => (
174+
<Stack.Screen
175+
key={name}
176+
name={name}
177+
getComponent={() => SCREENS[name].component}
178+
options={{ headerShown: false }}
179+
/>
180+
))}
181+
</Stack.Navigator>
182+
</NavigationContainer>
183+
</GestureDetectorProvider>
184+
</GestureHandlerRootView>
173185
);
174186

175187
const styles = StyleSheet.create({

Example/babel.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
module.exports = {
22
presets: ['module:metro-react-native-babel-preset'],
3-
plugins: [],
3+
plugins: ['react-native-reanimated/plugin'],
44
};

Example/ios/Podfile.lock

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -489,8 +489,12 @@ PODS:
489489
- React-jsi (= 0.72.4)
490490
- React-logger (= 0.72.4)
491491
- React-perflogger (= 0.72.4)
492-
- RNGestureHandler (2.12.1):
492+
- RNGestureHandler (2.13.1):
493493
- React-Core
494+
- RNReanimated (3.7.0-nightly-20240109-9e2c33716):
495+
- RCT-Folly (= 2021.07.22.00)
496+
- React-Core
497+
- ReactCommon/turbomodule/core
494498
- RNScreens (3.29.0):
495499
- RCT-Folly (= 2021.07.22.00)
496500
- React-Core
@@ -567,6 +571,7 @@ DEPENDENCIES:
567571
- React-utils (from `../node_modules/react-native/ReactCommon/react/utils`)
568572
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
569573
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
574+
- RNReanimated (from `../node_modules/react-native-reanimated`)
570575
- RNScreens (from `../node_modules/react-native-screens`)
571576
- RNVectorIcons (from `../node_modules/react-native-vector-icons`)
572577
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
@@ -672,6 +677,8 @@ EXTERNAL SOURCES:
672677
:path: "../node_modules/react-native/ReactCommon"
673678
RNGestureHandler:
674679
:path: "../node_modules/react-native-gesture-handler"
680+
RNReanimated:
681+
:path: "../node_modules/react-native-reanimated"
675682
RNScreens:
676683
:path: "../node_modules/react-native-screens"
677684
RNVectorIcons:
@@ -680,9 +687,9 @@ EXTERNAL SOURCES:
680687
:path: "../node_modules/react-native/ReactCommon/yoga"
681688

682689
SPEC CHECKSUMS:
683-
boost: 57d2868c099736d80fcd648bf211b4431e51a558
690+
boost: a7c83b31436843459a1961bfd74b96033dc77234
684691
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
685-
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
692+
DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662
686693
FBLazyVector: 5d4a3b7f411219a45a6d952f77d2c0a6c9989da5
687694
FBReactNativeSpec: 3fc2d478e1c4b08276f9dd9128f80ec6d5d85c1f
688695
Flipper: 6edb735e6c3e332975d1b17956bcc584eccf5818
@@ -694,7 +701,7 @@ SPEC CHECKSUMS:
694701
Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9
695702
FlipperKit: 2efad7007d6745a3f95e4034d547be637f89d3f6
696703
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
697-
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
704+
glog: 5337263514dd6f09803962437687240c5dc39aa4
698705
hermes-engine: 81191603c4eaa01f5e4ae5737a9efcf64756c7b2
699706
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
700707
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
@@ -732,13 +739,14 @@ SPEC CHECKSUMS:
732739
React-runtimescheduler: 4941cc1b3cf08b792fbf666342c9fc95f1969035
733740
React-utils: b79f2411931f9d3ea5781404dcbb2fa8a837e13a
734741
ReactCommon: 4b2bdcb50a3543e1c2b2849ad44533686610826d
735-
RNGestureHandler: c0d04458598fcb26052494ae23dda8f8f5162b13
736-
RNScreens: 3c5b9f4a9dcde752466854b6109b79c0e205dad3
742+
RNGestureHandler: 38aa38413896620338948fbb5c90579a7b1c3fde
743+
RNReanimated: 0f8173d46f45c2f690c416dff10206832631571d
744+
RNScreens: 975abd21a20b6ebd26563e5ab86b30250569c182
737745
RNVectorIcons: 31cebfcf94e8cf8686eb5303ae0357da64d7a5a4
738746
SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17
739747
Yoga: 3efc43e0d48686ce2e8c60f99d4e6bd349aff981
740748
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
741749

742750
PODFILE CHECKSUM: 86e380a4262db238c7a45428750af2d88465585c
743751

744-
COCOAPODS: 1.11.3
752+
COCOAPODS: 1.14.3

Example/metro.config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ const root = path.resolve(__dirname, '..');
1010
const modules = [
1111
'@react-navigation/native',
1212
'react-native-safe-area-context',
13+
'react-native-gesture-handler',
14+
'react-native-reanimated',
1315
...Object.keys(pack.peerDependencies),
1416
];
1517

Example/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
"nanoid": "^4.0.2",
2424
"react": "18.2.0",
2525
"react-native": "0.72.4",
26-
"react-native-gesture-handler": "^2.12.1",
26+
"react-native-gesture-handler": "^2.13.1",
27+
"react-native-reanimated": "3.7.0-nightly-20240109-9e2c33716",
2728
"react-native-restart": "^0.0.27",
2829
"react-native-safe-area-context": "^4.8.1",
2930
"react-native-screens": "link:../",
@@ -36,9 +37,9 @@
3637
"@react-native/eslint-config": "^0.72.2",
3738
"@react-native/metro-config": "^0.72.11",
3839
"@tsconfig/react-native": "^3.0.0",
40+
"@types/jest": "^29.2.5",
3941
"@types/react": "^18.0.24",
4042
"@types/react-native": "0.72.2",
41-
"@types/jest": "^29.2.5",
4243
"@types/react-native-restart": "^0.0.0",
4344
"@types/react-test-renderer": "^18.0.0",
4445
"babel-jest": "^29.3.1",
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import React from 'react';
2+
import { View, StyleSheet, I18nManager } from 'react-native';
3+
import {
4+
createNativeStackNavigator,
5+
NativeStackNavigationProp,
6+
} from 'react-native-screens/native-stack';
7+
import { Button } from '../shared';
8+
9+
type StackParamList = {
10+
ScreenA: undefined;
11+
ScreenB: undefined;
12+
ScreenC: undefined;
13+
};
14+
15+
interface MainScreenProps {
16+
navigation: NativeStackNavigationProp<StackParamList, 'ScreenA'>;
17+
}
18+
19+
const MainScreen = ({ navigation }: MainScreenProps): JSX.Element => (
20+
<View style={{ ...styles.container, backgroundColor: 'moccasin' }}>
21+
<Button title="Go ScreenB" onPress={() => navigation.navigate('ScreenB')} />
22+
<Button onPress={() => navigation.pop()} title="🔙 Back to Examples" />
23+
</View>
24+
);
25+
26+
interface ScreenBProps {
27+
navigation: NativeStackNavigationProp<StackParamList, 'ScreenB'>;
28+
}
29+
30+
const ScreenB = ({ navigation }: ScreenBProps): JSX.Element => (
31+
<View style={{ ...styles.container, backgroundColor: 'thistle' }}>
32+
<Button title="Go ScreenC" onPress={() => navigation.navigate('ScreenC')} />
33+
<Button title="Go back" onPress={() => navigation.goBack()} />
34+
</View>
35+
);
36+
37+
interface ScreenCProps {
38+
navigation: NativeStackNavigationProp<StackParamList, 'ScreenC'>;
39+
}
40+
41+
const ScreenC = ({ navigation }: ScreenCProps): JSX.Element => (
42+
<View style={{ ...styles.container, backgroundColor: 'blue' }}>
43+
<Button title="Go back" onPress={() => navigation.goBack()} />
44+
</View>
45+
);
46+
47+
const Stack = createNativeStackNavigator<StackParamList>();
48+
49+
const App = (): JSX.Element => (
50+
<Stack.Navigator
51+
screenOptions={{
52+
headerHideBackButton: true,
53+
stackAnimation: 'none',
54+
}}>
55+
<Stack.Screen name="ScreenA" component={MainScreen} />
56+
<Stack.Screen
57+
name="ScreenB"
58+
component={ScreenB}
59+
options={{
60+
goBackGesture: 'twoDimensionalSwipe',
61+
}}
62+
/>
63+
<Stack.Screen name="ScreenC" component={ScreenC} />
64+
</Stack.Navigator>
65+
);
66+
67+
const styles = StyleSheet.create({
68+
container: {
69+
flex: 1,
70+
paddingTop: 10,
71+
},
72+
});
73+
74+
export default App;

0 commit comments

Comments
 (0)