App.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. /* @flow */
  2. import React from 'react';
  3. import { Asset, Constants, ScreenOrientation } from 'expo';
  4. ScreenOrientation.allow(ScreenOrientation.Orientation.ALL);
  5. import {
  6. Animated,
  7. Image,
  8. Platform,
  9. ScrollView,
  10. StyleSheet,
  11. TouchableOpacity,
  12. Text,
  13. StatusBar,
  14. View,
  15. } from 'react-native';
  16. import { SafeAreaView, createStackNavigator } from 'react-navigation';
  17. import CustomTabs from './CustomTabs';
  18. import CustomTransitioner from './CustomTransitioner';
  19. import Drawer from './Drawer';
  20. import MultipleDrawer from './MultipleDrawer';
  21. import TabsInDrawer from './TabsInDrawer';
  22. import ModalStack from './ModalStack';
  23. import StacksInTabs from './StacksInTabs';
  24. import StacksOverTabs from './StacksOverTabs';
  25. import StacksOverTopTabs from './StacksOverTopTabs';
  26. import StacksWithKeys from './StacksWithKeys';
  27. import InactiveStack from './InactiveStack';
  28. import StackWithCustomHeaderBackImage from './StackWithCustomHeaderBackImage';
  29. import SimpleStack from './SimpleStack';
  30. import StackWithHeaderPreset from './StackWithHeaderPreset';
  31. import StackWithTranslucentHeader from './StackWithTranslucentHeader';
  32. import SimpleTabs from './SimpleTabs';
  33. import SwitchWithStacks from './SwitchWithStacks';
  34. import TabsWithNavigationFocus from './TabsWithNavigationFocus';
  35. import TabsWithNavigationEvents from './TabsWithNavigationEvents';
  36. import KeyboardHandlingExample from './KeyboardHandlingExample';
  37. const ExampleInfo = {
  38. SimpleStack: {
  39. name: 'Stack Example',
  40. description: 'A card stack',
  41. },
  42. SwitchWithStacks: {
  43. name: 'Switch between routes',
  44. description: 'Jump between routes',
  45. },
  46. InactiveStack: {
  47. name: 'Navigate idempotently to stacks in inactive routes',
  48. description:
  49. 'An inactive route in a stack should be given the opportunity to handle actions',
  50. },
  51. StackWithCustomHeaderBackImage: {
  52. name: 'Custom header back image',
  53. description: 'Stack with custom header back image',
  54. },
  55. SimpleTabs: {
  56. name: 'Tabs Example',
  57. description: 'Tabs following platform conventions',
  58. },
  59. Drawer: {
  60. name: 'Drawer Example',
  61. description: 'Android-style drawer navigation',
  62. },
  63. StackWithHeaderPreset: {
  64. name: 'UIKit-style Header Transitions',
  65. description: 'Masked back button and sliding header items. iOS only.',
  66. },
  67. StackWithTranslucentHeader: {
  68. name: 'Translucent Header',
  69. description: 'Render arbitrary translucent content in header background.',
  70. },
  71. // MultipleDrawer: {
  72. // name: 'Multiple Drawer Example',
  73. // description: 'Add any drawer you need',
  74. // },
  75. TabsInDrawer: {
  76. name: 'Drawer + Tabs Example',
  77. description: 'A drawer combined with tabs',
  78. },
  79. CustomTabs: {
  80. name: 'Custom Tabs',
  81. description: 'Custom tabs with tab router',
  82. },
  83. CustomTransitioner: {
  84. name: 'Custom Transitioner',
  85. description: 'Custom transitioner with stack router',
  86. },
  87. ModalStack: {
  88. name:
  89. Platform.OS === 'ios'
  90. ? 'Modal Stack Example'
  91. : 'Stack with Dynamic Header',
  92. description:
  93. Platform.OS === 'ios'
  94. ? 'Stack navigation with modals'
  95. : 'Dynamically showing and hiding the header',
  96. },
  97. StacksInTabs: {
  98. name: 'Stacks in Tabs',
  99. description: 'Nested stack navigation in tabs',
  100. },
  101. StacksOverTabs: {
  102. name: 'Stacks over Tabs',
  103. description: 'Nested stack navigation that pushes on top of tabs',
  104. },
  105. StacksOverTopTabs: {
  106. name: 'Stacks with non-standard header height',
  107. description: 'Tab navigator in stack with custom header heights',
  108. },
  109. StacksWithKeys: {
  110. name: 'Link in Stack with keys',
  111. description: 'Use keys to link between screens',
  112. },
  113. LinkStack: {
  114. name: 'Link in Stack',
  115. description: 'Deep linking into a route in stack',
  116. },
  117. LinkTabs: {
  118. name: 'Link to Settings Tab',
  119. description: 'Deep linking into a route in tab',
  120. },
  121. TabsWithNavigationFocus: {
  122. name: 'withNavigationFocus',
  123. description: 'Receive the focus prop to know when a screen is focused',
  124. },
  125. TabsWithNavigationEvents: {
  126. name: 'NavigationEvents',
  127. description:
  128. 'Declarative NavigationEvents component to subscribe to navigation events',
  129. },
  130. KeyboardHandlingExample: {
  131. name: 'Keyboard Handling Example',
  132. description:
  133. 'Demo automatic handling of keyboard showing/hiding inside StackNavigator',
  134. },
  135. };
  136. const ExampleRoutes = {
  137. SimpleStack,
  138. SwitchWithStacks,
  139. SimpleTabs: SimpleTabs,
  140. Drawer: Drawer,
  141. // MultipleDrawer: {
  142. // screen: MultipleDrawer,
  143. // },
  144. StackWithCustomHeaderBackImage: StackWithCustomHeaderBackImage,
  145. ...Platform.select({
  146. ios: {
  147. StackWithHeaderPreset: StackWithHeaderPreset,
  148. },
  149. android: {},
  150. }),
  151. StackWithTranslucentHeader: StackWithTranslucentHeader,
  152. TabsInDrawer: TabsInDrawer,
  153. CustomTabs: CustomTabs,
  154. CustomTransitioner: CustomTransitioner,
  155. ModalStack: ModalStack,
  156. StacksWithKeys: StacksWithKeys,
  157. StacksInTabs: StacksInTabs,
  158. StacksOverTabs: StacksOverTabs,
  159. StacksOverTopTabs: StacksOverTopTabs,
  160. LinkStack: {
  161. screen: SimpleStack,
  162. path: 'people/Jordan',
  163. },
  164. LinkTabs: {
  165. screen: SimpleTabs,
  166. path: 'settings',
  167. },
  168. TabsWithNavigationFocus,
  169. TabsWithNavigationEvents,
  170. KeyboardHandlingExample,
  171. // This is commented out because it's rarely useful
  172. // InactiveStack,
  173. };
  174. type State = {
  175. scrollY: Animated.Value,
  176. };
  177. class MainScreen extends React.Component<any, State> {
  178. state = {
  179. scrollY: new Animated.Value(0),
  180. };
  181. componentDidMount() {
  182. Asset.fromModule(
  183. require('react-navigation/src/views/assets/back-icon-mask.png')
  184. ).downloadAsync();
  185. Asset.fromModule(
  186. require('react-navigation/src/views/assets/back-icon.png')
  187. ).downloadAsync();
  188. }
  189. render() {
  190. const { navigation } = this.props;
  191. const scale = this.state.scrollY.interpolate({
  192. inputRange: [-450, 0, 100],
  193. outputRange: [2, 1, 0.8],
  194. extrapolate: 'clamp',
  195. });
  196. const translateY = this.state.scrollY.interpolate({
  197. inputRange: [-450, 0, 100],
  198. outputRange: [-150, 0, 40],
  199. });
  200. const opacity = this.state.scrollY.interpolate({
  201. inputRange: [0, 50],
  202. outputRange: [1, 0],
  203. extrapolate: 'clamp',
  204. });
  205. const underlayOpacity = this.state.scrollY.interpolate({
  206. inputRange: [0, 50],
  207. outputRange: [0, 1],
  208. extrapolate: 'clamp',
  209. });
  210. const backgroundScale = this.state.scrollY.interpolate({
  211. inputRange: [-450, 0],
  212. outputRange: [3, 1],
  213. extrapolate: 'clamp',
  214. });
  215. const backgroundTranslateY = this.state.scrollY.interpolate({
  216. inputRange: [-450, 0],
  217. outputRange: [0, 0],
  218. });
  219. return (
  220. <View style={{ flex: 1 }}>
  221. <Animated.ScrollView
  222. style={{ flex: 1 }}
  223. scrollEventThrottle={1}
  224. onScroll={Animated.event(
  225. [
  226. {
  227. nativeEvent: { contentOffset: { y: this.state.scrollY } },
  228. },
  229. ],
  230. { useNativeDriver: true }
  231. )}
  232. >
  233. <Animated.View
  234. style={[
  235. styles.backgroundUnderlay,
  236. {
  237. transform: [
  238. { scale: backgroundScale },
  239. { translateY: backgroundTranslateY },
  240. ],
  241. },
  242. ]}
  243. />
  244. <Animated.View
  245. style={{ opacity, transform: [{ scale }, { translateY }] }}
  246. >
  247. <SafeAreaView
  248. style={styles.bannerContainer}
  249. forceInset={{ top: 'always', bottom: 'never' }}
  250. >
  251. <View style={styles.banner}>
  252. <Image
  253. source={require('./assets/NavLogo.png')}
  254. style={styles.bannerImage}
  255. />
  256. <Text style={styles.bannerTitle}>
  257. React Navigation Examples
  258. </Text>
  259. </View>
  260. </SafeAreaView>
  261. </Animated.View>
  262. <SafeAreaView forceInset={{ bottom: 'always', horizontal: 'never' }}>
  263. <View style={{ backgroundColor: '#fff' }}>
  264. {Object.keys(ExampleRoutes).map((routeName: string) => (
  265. <TouchableOpacity
  266. key={routeName}
  267. onPress={() => {
  268. let route = ExampleRoutes[routeName];
  269. if (route.screen || route.path || route.params) {
  270. const { path, params, screen } = route;
  271. const { router } = screen;
  272. const action =
  273. path && router.getActionForPathAndParams(path, params);
  274. navigation.navigate(routeName, {}, action);
  275. } else {
  276. navigation.navigate(routeName);
  277. }
  278. }}
  279. >
  280. <SafeAreaView
  281. style={styles.itemContainer}
  282. forceInset={{ veritcal: 'never', bottom: 'never' }}
  283. >
  284. <View style={styles.item}>
  285. <Text style={styles.title}>
  286. {ExampleInfo[routeName].name}
  287. </Text>
  288. <Text style={styles.description}>
  289. {ExampleInfo[routeName].description}
  290. </Text>
  291. </View>
  292. </SafeAreaView>
  293. </TouchableOpacity>
  294. ))}
  295. </View>
  296. </SafeAreaView>
  297. </Animated.ScrollView>
  298. <StatusBar barStyle="light-content" />
  299. <Animated.View
  300. style={[styles.statusBarUnderlay, { opacity: underlayOpacity }]}
  301. />
  302. </View>
  303. );
  304. }
  305. }
  306. const AppNavigator = createStackNavigator(
  307. {
  308. ...ExampleRoutes,
  309. Index: {
  310. screen: MainScreen,
  311. },
  312. },
  313. {
  314. initialRouteName: 'Index',
  315. headerMode: 'none',
  316. /*
  317. * Use modal on iOS because the card mode comes from the right,
  318. * which conflicts with the drawer example gesture
  319. */
  320. mode: Platform.OS === 'ios' ? 'modal' : 'card',
  321. }
  322. );
  323. export default AppNavigator;
  324. const styles = StyleSheet.create({
  325. item: {
  326. paddingHorizontal: 16,
  327. paddingVertical: 12,
  328. },
  329. itemContainer: {
  330. backgroundColor: '#fff',
  331. borderBottomWidth: StyleSheet.hairlineWidth,
  332. borderBottomColor: '#ddd',
  333. },
  334. image: {
  335. width: 120,
  336. height: 120,
  337. alignSelf: 'center',
  338. marginBottom: 20,
  339. resizeMode: 'contain',
  340. },
  341. statusBarUnderlay: {
  342. backgroundColor: '#673ab7',
  343. position: 'absolute',
  344. top: 0,
  345. left: 0,
  346. right: 0,
  347. height: Constants.statusBarHeight,
  348. },
  349. title: {
  350. fontSize: 16,
  351. fontWeight: 'bold',
  352. color: '#444',
  353. },
  354. description: {
  355. fontSize: 13,
  356. color: '#999',
  357. },
  358. backgroundUnderlay: {
  359. backgroundColor: '#673ab7',
  360. position: 'absolute',
  361. top: -100,
  362. height: 300,
  363. left: 0,
  364. right: 0,
  365. },
  366. bannerContainer: {
  367. // backgroundColor: '#673ab7',
  368. alignItems: 'center',
  369. },
  370. banner: {
  371. flexDirection: 'row',
  372. alignItems: 'center',
  373. padding: 16,
  374. },
  375. bannerImage: {
  376. width: 36,
  377. height: 36,
  378. resizeMode: 'contain',
  379. tintColor: '#fff',
  380. margin: 8,
  381. },
  382. bannerTitle: {
  383. fontSize: 18,
  384. fontWeight: '200',
  385. color: '#fff',
  386. marginVertical: 8,
  387. marginRight: 5,
  388. },
  389. });