├── assets ├── icon.png ├── favicon.png ├── splash.png └── adaptive-icon.png ├── babel.config.js ├── examples ├── 12-pokedex │ ├── assets │ │ ├── pokeball.png │ │ ├── type-bug.png │ │ ├── type-dark.png │ │ ├── type-fairy.png │ │ ├── type-fire.png │ │ ├── type-ghost.png │ │ ├── type-grass.png │ │ ├── type-ice.png │ │ ├── type-rock.png │ │ ├── type-steel.png │ │ ├── type-water.png │ │ ├── move-active.png │ │ ├── type-dragon.png │ │ ├── type-flying.png │ │ ├── type-ground.png │ │ ├── type-normal.png │ │ ├── type-poison.png │ │ ├── type-psychic.png │ │ ├── pokemon-active.png │ │ ├── type-electric.png │ │ └── type-fighting.png │ ├── components │ │ ├── PokemonType.js │ │ ├── MainHeader.js │ │ └── PokemonStatus.js │ ├── constants.js │ ├── Pokedex.js │ └── screens │ │ ├── MoveDetail.js │ │ ├── MoveList.js │ │ ├── PokemonList.js │ │ └── PokemonDetail.js ├── 3-the-light │ ├── assets │ │ ├── bulb-off.jpg │ │ ├── bulb-on.jpg │ │ ├── traffic-light.png │ │ ├── traffic-light-green.png │ │ ├── traffic-light-red.png │ │ └── traffic-light-yellow.png │ ├── 1.TheLight.js │ └── 2.TrafficLight.js ├── 5-instagram-feed │ ├── assets │ │ ├── img1.jpg │ │ ├── img2.jpg │ │ ├── img3.jpg │ │ ├── img4.jpg │ │ ├── img5.jpg │ │ ├── avatar.png │ │ ├── avatar1.jpg │ │ ├── avatar2.jpg │ │ ├── avatar3.jpg │ │ └── avatar4.jpg │ ├── components │ │ ├── Stories.js │ │ ├── Header.js │ │ ├── Story.js │ │ └── Article.js │ ├── data.js │ └── InstagramFeed.js ├── 2-login-screen │ ├── assets │ │ └── facebook-banner.jpg │ ├── 1.MomoLogin.js │ └── 2.FacebookLogin.js ├── 10-music-player │ ├── assets │ │ ├── slider-thumb-ios.png │ │ └── slider-thumb-android.png │ ├── style.js │ ├── util.js │ ├── MusicPlayer.style.js │ ├── listSong.js │ ├── PlayerModal.style.js │ ├── PlayerModal.js │ └── MusicPlayer.js ├── 9-bmi-calculator │ ├── assets │ │ └── slider-thumb-image.png │ ├── const.js │ ├── components │ │ ├── Button.js │ │ ├── GenderSelection.js │ │ ├── HeightSelection.js │ │ ├── ResultModal.js │ │ └── UnitSelection.js │ ├── style.js │ └── BMICalculator.js ├── 11-news │ ├── apis.js │ ├── Article.js │ └── WorldwideNews.js ├── 4-register-form │ ├── validation.js │ ├── FormField.js │ ├── styles.js │ └── RegisterForm.js ├── 1-hello-world │ ├── 1.HelloWorld1.js │ └── 2.HelloWorld2.js ├── 8-stopwatch │ ├── util.js │ ├── Result.js │ ├── Control.js │ └── StopWatch.js ├── 6-rock-paper-scissors │ ├── Actions.js │ ├── DisplayResult.js │ └── RockPaperScissors.js └── 7-scan-qr-code │ ├── ScannerView.js │ └── ScanQrCode.js ├── .gitignore ├── .eslintrc.js ├── app.json ├── package.json ├── App.js ├── example-list.js ├── README.md └── LICENSE /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/assets/icon.png -------------------------------------------------------------------------------- /assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/assets/favicon.png -------------------------------------------------------------------------------- /assets/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/assets/splash.png -------------------------------------------------------------------------------- /assets/adaptive-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/assets/adaptive-icon.png -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function(api) { 2 | api.cache(true); 3 | return { 4 | presets: ['babel-preset-expo'], 5 | }; 6 | }; 7 | -------------------------------------------------------------------------------- /examples/12-pokedex/assets/pokeball.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/12-pokedex/assets/pokeball.png -------------------------------------------------------------------------------- /examples/12-pokedex/assets/type-bug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/12-pokedex/assets/type-bug.png -------------------------------------------------------------------------------- /examples/12-pokedex/assets/type-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/12-pokedex/assets/type-dark.png -------------------------------------------------------------------------------- /examples/12-pokedex/assets/type-fairy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/12-pokedex/assets/type-fairy.png -------------------------------------------------------------------------------- /examples/12-pokedex/assets/type-fire.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/12-pokedex/assets/type-fire.png -------------------------------------------------------------------------------- /examples/12-pokedex/assets/type-ghost.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/12-pokedex/assets/type-ghost.png -------------------------------------------------------------------------------- /examples/12-pokedex/assets/type-grass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/12-pokedex/assets/type-grass.png -------------------------------------------------------------------------------- /examples/12-pokedex/assets/type-ice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/12-pokedex/assets/type-ice.png -------------------------------------------------------------------------------- /examples/12-pokedex/assets/type-rock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/12-pokedex/assets/type-rock.png -------------------------------------------------------------------------------- /examples/12-pokedex/assets/type-steel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/12-pokedex/assets/type-steel.png -------------------------------------------------------------------------------- /examples/12-pokedex/assets/type-water.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/12-pokedex/assets/type-water.png -------------------------------------------------------------------------------- /examples/3-the-light/assets/bulb-off.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/3-the-light/assets/bulb-off.jpg -------------------------------------------------------------------------------- /examples/3-the-light/assets/bulb-on.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/3-the-light/assets/bulb-on.jpg -------------------------------------------------------------------------------- /examples/5-instagram-feed/assets/img1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/5-instagram-feed/assets/img1.jpg -------------------------------------------------------------------------------- /examples/5-instagram-feed/assets/img2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/5-instagram-feed/assets/img2.jpg -------------------------------------------------------------------------------- /examples/5-instagram-feed/assets/img3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/5-instagram-feed/assets/img3.jpg -------------------------------------------------------------------------------- /examples/5-instagram-feed/assets/img4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/5-instagram-feed/assets/img4.jpg -------------------------------------------------------------------------------- /examples/5-instagram-feed/assets/img5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/5-instagram-feed/assets/img5.jpg -------------------------------------------------------------------------------- /examples/12-pokedex/assets/move-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/12-pokedex/assets/move-active.png -------------------------------------------------------------------------------- /examples/12-pokedex/assets/type-dragon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/12-pokedex/assets/type-dragon.png -------------------------------------------------------------------------------- /examples/12-pokedex/assets/type-flying.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/12-pokedex/assets/type-flying.png -------------------------------------------------------------------------------- /examples/12-pokedex/assets/type-ground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/12-pokedex/assets/type-ground.png -------------------------------------------------------------------------------- /examples/12-pokedex/assets/type-normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/12-pokedex/assets/type-normal.png -------------------------------------------------------------------------------- /examples/12-pokedex/assets/type-poison.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/12-pokedex/assets/type-poison.png -------------------------------------------------------------------------------- /examples/12-pokedex/assets/type-psychic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/12-pokedex/assets/type-psychic.png -------------------------------------------------------------------------------- /examples/5-instagram-feed/assets/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/5-instagram-feed/assets/avatar.png -------------------------------------------------------------------------------- /examples/12-pokedex/assets/pokemon-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/12-pokedex/assets/pokemon-active.png -------------------------------------------------------------------------------- /examples/12-pokedex/assets/type-electric.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/12-pokedex/assets/type-electric.png -------------------------------------------------------------------------------- /examples/12-pokedex/assets/type-fighting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/12-pokedex/assets/type-fighting.png -------------------------------------------------------------------------------- /examples/3-the-light/assets/traffic-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/3-the-light/assets/traffic-light.png -------------------------------------------------------------------------------- /examples/5-instagram-feed/assets/avatar1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/5-instagram-feed/assets/avatar1.jpg -------------------------------------------------------------------------------- /examples/5-instagram-feed/assets/avatar2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/5-instagram-feed/assets/avatar2.jpg -------------------------------------------------------------------------------- /examples/5-instagram-feed/assets/avatar3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/5-instagram-feed/assets/avatar3.jpg -------------------------------------------------------------------------------- /examples/5-instagram-feed/assets/avatar4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/5-instagram-feed/assets/avatar4.jpg -------------------------------------------------------------------------------- /examples/2-login-screen/assets/facebook-banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/2-login-screen/assets/facebook-banner.jpg -------------------------------------------------------------------------------- /examples/3-the-light/assets/traffic-light-green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/3-the-light/assets/traffic-light-green.png -------------------------------------------------------------------------------- /examples/3-the-light/assets/traffic-light-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/3-the-light/assets/traffic-light-red.png -------------------------------------------------------------------------------- /examples/10-music-player/assets/slider-thumb-ios.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/10-music-player/assets/slider-thumb-ios.png -------------------------------------------------------------------------------- /examples/3-the-light/assets/traffic-light-yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/3-the-light/assets/traffic-light-yellow.png -------------------------------------------------------------------------------- /examples/10-music-player/assets/slider-thumb-android.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/10-music-player/assets/slider-thumb-android.png -------------------------------------------------------------------------------- /examples/9-bmi-calculator/assets/slider-thumb-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinhuy/react-native-expo-examples/HEAD/examples/9-bmi-calculator/assets/slider-thumb-image.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .expo 3 | expo-env.d.ts 4 | npm-debug.* 5 | *.jks 6 | *.p8 7 | *.p12 8 | *.key 9 | *.mobileprovision 10 | *.orig.* 11 | web-build/ 12 | dist 13 | 14 | # macOS 15 | .DS_Store 16 | -------------------------------------------------------------------------------- /examples/10-music-player/style.js: -------------------------------------------------------------------------------- 1 | export const PRIMARY_COLOR = "#f39220"; 2 | export const PRIMARY_TEXT_COLOR = "#686868"; 3 | export const SECONDARY_TEXT_COLOR = "#9a9a9a"; 4 | 5 | export const ROW = { 6 | flexDirection: "row", 7 | justifyContent: "space-between", 8 | }; 9 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | // https://docs.expo.dev/guides/using-eslint/ 2 | module.exports = { 3 | extends: 'expo', 4 | globals: { 5 | setTimeout: 'readonly', 6 | clearTimeout: 'readonly', 7 | setInterval: 'readonly', 8 | clearInterval: 'readonly', 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /examples/9-bmi-calculator/const.js: -------------------------------------------------------------------------------- 1 | export const DEFAULT_VALUE = { 2 | gender: "male", 3 | height: 150, 4 | weight: 50, 5 | age: 20, 6 | }; 7 | export const MIN_WEIGHT = 10; 8 | export const MAX_WEIGHT = 150; 9 | export const MIN_AGE = 1; 10 | export const MAX_AGE = 150; 11 | -------------------------------------------------------------------------------- /examples/10-music-player/util.js: -------------------------------------------------------------------------------- 1 | const padToTwo = (number) => (number <= 9 ? `0${number}` : number); 2 | 3 | export const displayTime = (milliSeconds) => { 4 | let minutes = 0; 5 | let seconds = Math.round(milliSeconds / 1000); 6 | let remainSeconds = seconds % 60; 7 | minutes = (seconds - remainSeconds) / 60; 8 | return `${padToTwo(minutes)}:${padToTwo(remainSeconds)}`; 9 | }; 10 | -------------------------------------------------------------------------------- /examples/11-news/apis.js: -------------------------------------------------------------------------------- 1 | // Register API Key here for more requests & APIs: https://newsapi.org 2 | const API_KEY = "ce52845d6e754123b3ecf9f68006b846"; 3 | 4 | export async function getNews(page = 1, pageSize = 10) { 5 | try { 6 | const response = await fetch( 7 | `https://newsapi.org/v2/top-headlines?language=en&page=${page}&pageSize=${pageSize}&apiKey=${API_KEY}` 8 | ); 9 | const jsonData = await response.json(); 10 | return jsonData.articles || []; 11 | } catch { 12 | return []; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/12-pokedex/components/PokemonType.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { ActivityIndicator } from "react-native"; 3 | import { Image } from "react-native-elements"; 4 | import { PokemonTypeIcon } from "../constants"; 5 | 6 | export default function PokemonType({ type }) { 7 | return ( 8 | } 13 | /> 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /examples/4-register-form/validation.js: -------------------------------------------------------------------------------- 1 | import * as Yup from "yup"; 2 | 3 | // https://github.com/jquense/yup 4 | export const validationSchema = Yup.object().shape({ 5 | firstName: Yup.string().required("First Name is required"), 6 | lastName: Yup.string().required("Last Name is required"), 7 | email: Yup.string() 8 | .email("Enter a valid email") 9 | .required("Please enter a registered email"), 10 | password: Yup.string() 11 | .required("Please enter a password") 12 | .min(6, "Password must have at least 6 characters"), 13 | confirmPassword: Yup.string() 14 | .required("Please confirm password") 15 | .oneOf([Yup.ref("password")], "Password & Confirm Password does not match"), 16 | }); 17 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "react-native-expo-examples", 4 | "slug": "react-native-expo-examples", 5 | "version": "1.0.0", 6 | "orientation": "portrait", 7 | "icon": "./assets/icon.png", 8 | "userInterfaceStyle": "light", 9 | "splash": { 10 | "image": "./assets/splash.png", 11 | "resizeMode": "contain", 12 | "backgroundColor": "#ffffff" 13 | }, 14 | "ios": { 15 | "supportsTablet": true 16 | }, 17 | "android": { 18 | "adaptiveIcon": { 19 | "foregroundImage": "./assets/adaptive-icon.png", 20 | "backgroundColor": "#ffffff" 21 | } 22 | }, 23 | "web": { 24 | "favicon": "./assets/favicon.png" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/1-hello-world/1.HelloWorld1.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Text, View } from "react-native"; 3 | 4 | export default function HelloWorld1() { 5 | return ( 6 | // https://reactnative.dev/docs/view 7 | 15 | {/* https://reactnative.dev/docs/text */} 16 | 24 | Hello world! 25 | 26 | 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /examples/5-instagram-feed/components/Stories.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { ScrollView } from "react-native"; 3 | import { profile, stories } from "../data"; 4 | import Story from "./Story"; 5 | 6 | export default function Stories() { 7 | return ( 8 | // https://reactnative.dev/docs/scrollview 9 | 10 | 11 | 12 | {stories.map((story) => ( 13 | 19 | ))} 20 | 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /examples/8-stopwatch/util.js: -------------------------------------------------------------------------------- 1 | const padToTwo = (number) => (number <= 9 ? `0${number}` : number); 2 | 3 | export const displayTime = (centiseconds) => { 4 | let minutes = 0; 5 | let seconds = 0; 6 | 7 | if (centiseconds < 0) { 8 | centiseconds = 0; 9 | } 10 | 11 | if (centiseconds < 100) { 12 | return `00:00,${padToTwo(centiseconds)}`; 13 | } 14 | 15 | let remainCentiseconds = centiseconds % 100; 16 | seconds = (centiseconds - remainCentiseconds) / 100; 17 | 18 | if (seconds < 60) { 19 | return `00:${padToTwo(seconds)},${padToTwo(remainCentiseconds)}`; 20 | } 21 | 22 | let remainSeconds = seconds % 60; 23 | minutes = (seconds - remainSeconds) / 60; 24 | 25 | return `${padToTwo(minutes)}:${padToTwo(remainSeconds)}:${padToTwo( 26 | remainCentiseconds 27 | )}`; 28 | }; 29 | -------------------------------------------------------------------------------- /examples/9-bmi-calculator/components/Button.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Platform, StyleSheet, Text, TouchableOpacity } from "react-native"; 3 | import { CENTER, TEXT } from "../style"; 4 | 5 | function Button({ title, onPress }) { 6 | return ( 7 | 8 | {title} 9 | 10 | ); 11 | } 12 | 13 | const styles = StyleSheet.create({ 14 | button: { 15 | ...CENTER, 16 | height: 60, 17 | borderRadius: 5, 18 | backgroundColor: "#e83d66", 19 | marginTop: 15, 20 | marginBottom: Platform.OS === "ios" ? 0 : 10, 21 | }, 22 | buttonText: { 23 | ...TEXT, 24 | fontSize: 24, 25 | fontWeight: "bold", 26 | }, 27 | }); 28 | 29 | export default React.memo(Button); 30 | -------------------------------------------------------------------------------- /examples/5-instagram-feed/components/Header.js: -------------------------------------------------------------------------------- 1 | import { Feather } from "@expo/vector-icons"; 2 | import React from "react"; 3 | import { Image, StyleSheet, TouchableOpacity } from "react-native"; 4 | 5 | const INSTAGRAM_LOGO = 6 | "https://upload.wikimedia.org/wikipedia/commons/thumb/2/2a/Instagram_logo.svg/1200px-Instagram_logo.svg.png"; 7 | 8 | export default function Header() { 9 | return ( 10 | <> 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ); 22 | } 23 | 24 | const styles = StyleSheet.create({ 25 | logo: { 26 | flex: 1, 27 | height: 30, 28 | resizeMode: "contain", 29 | }, 30 | }); 31 | -------------------------------------------------------------------------------- /examples/9-bmi-calculator/style.js: -------------------------------------------------------------------------------- 1 | import { Platform } from "react-native"; 2 | 3 | export const BG_COLOR = "#323344"; 4 | export const HIGHLIGHT_BG_COLOR = "#24263b"; 5 | 6 | export const TEXT = { 7 | color: "#fff", 8 | textAlign: "center", 9 | }; 10 | 11 | export const TEXT_LABEL = { 12 | fontSize: 15, 13 | textAlign: "center", 14 | color: "#848694", 15 | }; 16 | 17 | export const TEXT_VALUE = { 18 | ...TEXT, 19 | fontFamily: Platform.OS === "ios" ? "Helvetica Neue" : null, 20 | fontSize: 35, 21 | lineHeight: 55, 22 | fontWeight: "bold", 23 | }; 24 | 25 | export const ROW = { 26 | flex: 1, 27 | flexDirection: "row", 28 | justifyContent: "space-between", 29 | }; 30 | 31 | export const CENTER = { 32 | justifyContent: "center", 33 | alignItems: "center", 34 | }; 35 | 36 | export const BOX = { 37 | flex: 1, 38 | backgroundColor: BG_COLOR, 39 | padding: 15, 40 | borderRadius: 10, 41 | }; 42 | -------------------------------------------------------------------------------- /examples/4-register-form/FormField.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Text, TextInput, View } from "react-native"; 3 | import { styles } from "./styles"; 4 | 5 | export default function FormField({ 6 | field, 7 | label, 8 | secureTextEntry, 9 | autoCapitalize, 10 | values, 11 | touched, 12 | errors, 13 | handleChange, 14 | handleBlur, 15 | }) { 16 | return ( 17 | 18 | {label} 19 | 20 | 28 | 29 | {touched[field] && errors[field] ? ( 30 | 31 | {errors[field]} 32 | 33 | ) : null} 34 | 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /examples/12-pokedex/components/MainHeader.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Header, Icon } from "react-native-elements"; 3 | import { BackgroundColor } from "../constants"; 4 | 5 | export default function MainHeader({ navigation, isMain, title }) { 6 | if (isMain) { 7 | return ( 8 |
14 | ); 15 | } else { 16 | return ( 17 |
{ 28 | navigation.goBack(); 29 | }} 30 | /> 31 | } 32 | centerComponent={{ text: title, style: { color: "#fff" } }} 33 | /> 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /examples/8-stopwatch/Result.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { ScrollView, StyleSheet, Text, View } from "react-native"; 3 | import { displayTime } from "./util"; 4 | 5 | function Result({ results }) { 6 | // console.log(results); 7 | return ( 8 | 9 | 10 | 11 | {results.map((item, index) => ( 12 | 13 | 14 | Step {results.length - index} 15 | 16 | 17 | {displayTime(item)} 18 | 19 | ))} 20 | 21 | ); 22 | } 23 | 24 | const styles = StyleSheet.create({ 25 | resultItem: { 26 | flexDirection: "row", 27 | justifyContent: "space-between", 28 | alignItems: "center", 29 | borderBottomWidth: 1, 30 | borderColor: "#313131", 31 | height: 50, 32 | paddingHorizontal: 15, 33 | }, 34 | resultItemText: { color: "#fff" }, 35 | }); 36 | 37 | // https://reactjs.org/docs/react-api.html#reactmemo 38 | export default React.memo(Result); 39 | -------------------------------------------------------------------------------- /examples/9-bmi-calculator/components/GenderSelection.js: -------------------------------------------------------------------------------- 1 | import { FontAwesome5 } from "@expo/vector-icons"; 2 | import React from "react"; 3 | import { StyleSheet, Text, TouchableOpacity } from "react-native"; 4 | import { 5 | BG_COLOR, 6 | BOX, 7 | CENTER, 8 | HIGHLIGHT_BG_COLOR, 9 | TEXT_LABEL, 10 | } from "../style"; 11 | 12 | function GenderSelection({ label, iconName, iconColor, isActive, setActive }) { 13 | return ( 14 | 23 | 24 | {label} 25 | 26 | ); 27 | } 28 | 29 | const styles = StyleSheet.create({ 30 | box: { 31 | ...CENTER, 32 | ...BOX, 33 | marginHorizontal: 10, 34 | }, 35 | label: { 36 | ...TEXT_LABEL, 37 | marginTop: 10, 38 | }, 39 | }); 40 | 41 | // https://reactjs.org/docs/react-api.html#reactmemo 42 | export default React.memo(GenderSelection); 43 | -------------------------------------------------------------------------------- /examples/10-music-player/MusicPlayer.style.js: -------------------------------------------------------------------------------- 1 | import Constants from "expo-constants"; 2 | import { StyleSheet } from "react-native"; 3 | import { 4 | PRIMARY_COLOR, 5 | PRIMARY_TEXT_COLOR, 6 | ROW, 7 | SECONDARY_TEXT_COLOR, 8 | } from "./style"; 9 | 10 | export const styles = StyleSheet.create({ 11 | container: { 12 | flex: 1, 13 | paddingTop: Constants.statusBarHeight, 14 | }, 15 | header: { 16 | padding: 15, 17 | marginBottom: 10, 18 | }, 19 | headerTitle: { 20 | fontWeight: "bold", 21 | fontSize: 24, 22 | color: PRIMARY_COLOR, 23 | }, 24 | listItem: { 25 | flexDirection: "row", 26 | margin: 15, 27 | }, 28 | coverImage: { 29 | width: 60, 30 | height: 60, 31 | borderRadius: 6, 32 | marginRight: 15, 33 | }, 34 | songName: { 35 | fontWeight: "bold", 36 | fontSize: 16, 37 | lineHeight: 24, 38 | color: PRIMARY_TEXT_COLOR, 39 | }, 40 | songInfo: { 41 | ...ROW, 42 | flex: 1, 43 | marginTop: 10, 44 | }, 45 | singerName: { 46 | fontSize: 14, 47 | color: SECONDARY_TEXT_COLOR, 48 | }, 49 | songDuration: { 50 | fontSize: 14, 51 | color: SECONDARY_TEXT_COLOR, 52 | }, 53 | }); 54 | -------------------------------------------------------------------------------- /examples/12-pokedex/components/PokemonStatus.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { StyleSheet, Text, View } from "react-native"; 3 | import ProgressBar from "react-native-progress/Bar"; 4 | 5 | export default function PokemonStatus({ title, value, progress }) { 6 | return ( 7 | 8 | {title} 9 | {value} 10 | 11 | {/* https://github.com/oblador/react-native-progress */} 12 | 21 | 22 | 23 | ); 24 | } 25 | 26 | const styles = StyleSheet.create({ 27 | pokemonStatus: { 28 | flexDirection: "row", 29 | alignItems: "center", 30 | marginBottom: 10, 31 | }, 32 | pokemonStatusName: { 33 | color: "#1a87d9", 34 | fontWeight: "bold", 35 | flex: 1 / 7, 36 | }, 37 | pokemonStatusPoint: { 38 | paddingHorizontal: 10, 39 | flex: 1 / 7, 40 | }, 41 | pokemonStatusBar: { 42 | flex: 5 / 7, 43 | }, 44 | }); 45 | -------------------------------------------------------------------------------- /examples/12-pokedex/constants.js: -------------------------------------------------------------------------------- 1 | const FullPokemonsAPI = 2 | "https://gamepress.gg/sites/default/files/aggregatedjson/pokemon-data-full-en-PoGO.json"; 3 | const FullMovesAPI = 4 | "https://gamepress.gg/sites/default/files/aggregatedjson/move-data-full-PoGO.json"; 5 | 6 | const PokemonTypeIcon = { 7 | bug: require("./assets/type-bug.png"), 8 | dark: require("./assets/type-dark.png"), 9 | dragon: require("./assets/type-dragon.png"), 10 | electric: require("./assets/type-electric.png"), 11 | fairy: require("./assets/type-fairy.png"), 12 | fighting: require("./assets/type-fighting.png"), 13 | fire: require("./assets/type-fire.png"), 14 | flying: require("./assets/type-flying.png"), 15 | ghost: require("./assets/type-ghost.png"), 16 | grass: require("./assets/type-grass.png"), 17 | ground: require("./assets/type-ground.png"), 18 | ice: require("./assets/type-ice.png"), 19 | normal: require("./assets/type-normal.png"), 20 | poison: require("./assets/type-poison.png"), 21 | psychic: require("./assets/type-psychic.png"), 22 | rock: require("./assets/type-rock.png"), 23 | steel: require("./assets/type-steel.png"), 24 | water: require("./assets/type-water.png"), 25 | default: require("./assets/type-ice.png"), 26 | }; 27 | 28 | const BackgroundColor = "#559EDF"; 29 | 30 | export { FullPokemonsAPI, FullMovesAPI, PokemonTypeIcon, BackgroundColor }; 31 | -------------------------------------------------------------------------------- /examples/1-hello-world/2.HelloWorld2.js: -------------------------------------------------------------------------------- 1 | import Constants from "expo-constants"; 2 | import React from "react"; 3 | import { SafeAreaView, StyleSheet, Text } from "react-native"; 4 | 5 | export default function HelloWorld2() { 6 | return ( 7 | // https://reactnative.dev/docs/safeareaview 8 | 9 | 10 | Hello World 11 | 12 | 13 | 14 | Hello World 15 | 16 | 17 | 18 | Hello World 19 | 20 | 21 | ); 22 | } 23 | 24 | // https://reactnative.dev/docs/stylesheet 25 | const styles = StyleSheet.create({ 26 | container: { 27 | // SafeAreaView on Android devices 28 | paddingTop: Constants.statusBarHeight, 29 | }, 30 | heading: { 31 | marginTop: 50, 32 | textAlign: "center", 33 | fontSize: 30, 34 | fontWeight: "bold", 35 | textTransform: "uppercase", 36 | }, 37 | highlightText1: { 38 | color: "#e74c3c", 39 | }, 40 | highlightText2: { 41 | fontStyle: "italic", 42 | textDecorationLine: "underline", 43 | color: "#2980b9", 44 | }, 45 | highlightText3: { 46 | color: "#fff", 47 | backgroundColor: "#59595d", 48 | }, 49 | }); 50 | -------------------------------------------------------------------------------- /examples/10-music-player/listSong.js: -------------------------------------------------------------------------------- 1 | export const PLAY_LIST = [ 2 | { 3 | sourceUri: 4 | "https://github.com/robinhuy/robinhuy/blob/master/musics/hoa-hai-duong.mp3?raw=true", 5 | name: "Hoa Hải Đường", 6 | coverImage: 7 | "https://user-images.githubusercontent.com/12640832/100078185-d4224880-2e75-11eb-8cc0-e09b3dce7c7a.jpg", 8 | singer: "Jack", 9 | duration: 229632, 10 | }, 11 | { 12 | sourceUri: 13 | "https://github.com/robinhuy/robinhuy/blob/master/musics/ai-mang-co-don-di.mp3?raw=true", 14 | name: "Ai Mang Cô Đơn Đi", 15 | coverImage: 16 | "https://user-images.githubusercontent.com/12640832/100081249-637d2b00-2e79-11eb-924b-0b4cdd4e1f9a.jpg", 17 | singer: "K-ICM, APJ", 18 | duration: 221231, 19 | }, 20 | { 21 | sourceUri: 22 | "https://github.com/robinhuy/robinhuy/blob/master/musics/bong-hoa-dep-nhat.mp3?raw=true", 23 | name: "Bông Hoa Đẹp Nhất", 24 | coverImage: 25 | "https://user-images.githubusercontent.com/12640832/100080805-d76b0380-2e78-11eb-9aad-648e5cd1749e.jpg", 26 | singer: "Quân A.P", 27 | duration: 315312, 28 | }, 29 | { 30 | sourceUri: 31 | "https://github.com/robinhuy/robinhuy/blob/master/musics/thien-dang.mp3?raw=true", 32 | name: "Thiên Đàng", 33 | coverImage: 34 | "https://user-images.githubusercontent.com/12640832/100080888-f10c4b00-2e78-11eb-931c-74272c77cad4.jpg", 35 | singer: "Wowy, JoliPoli", 36 | duration: 232200, 37 | }, 38 | ]; 39 | -------------------------------------------------------------------------------- /examples/10-music-player/PlayerModal.style.js: -------------------------------------------------------------------------------- 1 | import { Platform, StyleSheet } from "react-native"; 2 | import { PRIMARY_TEXT_COLOR, ROW, SECONDARY_TEXT_COLOR } from "./style"; 3 | 4 | export const styles = StyleSheet.create({ 5 | container: { 6 | flex: 1, 7 | backgroundColor: "#fff", 8 | }, 9 | content: { 10 | padding: 20, 11 | }, 12 | closeButton: { 13 | alignItems: "flex-end", 14 | height: 40, 15 | paddingHorizontal: 15, 16 | }, 17 | coverImage: { 18 | width: 200, 19 | height: 200, 20 | borderRadius: 20, 21 | alignSelf: "center", 22 | }, 23 | songName: { 24 | fontWeight: "bold", 25 | fontSize: 20, 26 | color: PRIMARY_TEXT_COLOR, 27 | marginTop: 20, 28 | alignSelf: "center", 29 | }, 30 | singerName: { 31 | fontSize: 16, 32 | color: SECONDARY_TEXT_COLOR, 33 | marginTop: 5, 34 | fontStyle: "italic", 35 | alignSelf: "center", 36 | }, 37 | progress: { 38 | margin: 30, 39 | }, 40 | time: { 41 | ...ROW, 42 | marginHorizontal: Platform.OS === "android" ? 15 : 0, 43 | }, 44 | timeText: { 45 | color: "#757575", 46 | }, 47 | slider: { 48 | height: 30, 49 | }, 50 | controls: { 51 | flexDirection: "row", 52 | justifyContent: "center", 53 | alignItems: "center", 54 | marginHorizontal: 30, 55 | }, 56 | primaryControlIcon: { 57 | fontSize: 50, 58 | color: "#f27637", 59 | marginHorizontal: 25, 60 | }, 61 | secondaryControlIcon: { 62 | fontSize: 25, 63 | color: PRIMARY_TEXT_COLOR, 64 | }, 65 | }); 66 | -------------------------------------------------------------------------------- /examples/4-register-form/styles.js: -------------------------------------------------------------------------------- 1 | import Constants from "expo-constants"; 2 | import { Platform, StyleSheet } from "react-native"; 3 | 4 | const HEADER_BACKGROUND = "#3498db"; 5 | const CONTENT_BACKGROUND = "#f9f9f9"; 6 | 7 | export const styles = StyleSheet.create({ 8 | topSafeArea: { 9 | backgroundColor: HEADER_BACKGROUND, 10 | }, 11 | container: { 12 | flex: 1, 13 | paddingTop: Constants.statusBarHeight, 14 | backgroundColor: 15 | Platform.OS === "ios" ? CONTENT_BACKGROUND : HEADER_BACKGROUND, 16 | }, 17 | header: { 18 | height: 60, 19 | justifyContent: "center", 20 | alignItems: "center", 21 | backgroundColor: HEADER_BACKGROUND, 22 | }, 23 | headerText: { 24 | color: "#fff", 25 | fontSize: 18, 26 | }, 27 | content: { 28 | padding: 20, 29 | backgroundColor: CONTENT_BACKGROUND, 30 | }, 31 | formGroup: { 32 | marginBottom: 10, 33 | }, 34 | label: { 35 | color: "#7d7e79", 36 | fontSize: 16, 37 | lineHeight: 30, 38 | }, 39 | input: { 40 | height: 50, 41 | paddingHorizontal: 20, 42 | borderRadius: 5, 43 | borderWidth: 2, 44 | borderColor: "#e3e3e3", 45 | backgroundColor: "#fff", 46 | }, 47 | errorContainer: { 48 | marginVertical: 5, 49 | }, 50 | errorText: { 51 | color: "#ff7675", 52 | }, 53 | button: { 54 | marginTop: 20, 55 | backgroundColor: "#2980b9", 56 | padding: 15, 57 | borderRadius: 15, 58 | }, 59 | buttonText: { 60 | color: "#fff", 61 | fontWeight: "bold", 62 | fontSize: 18, 63 | textAlign: "center", 64 | }, 65 | }); 66 | -------------------------------------------------------------------------------- /examples/6-rock-paper-scissors/Actions.js: -------------------------------------------------------------------------------- 1 | import { FontAwesome5 } from "@expo/vector-icons"; 2 | import React from "react"; 3 | import { StyleSheet, TouchableOpacity, View } from "react-native"; 4 | 5 | export default function Actions({ play, canPlay }) { 6 | return ( 7 | 8 | play(1)} 12 | > 13 | 14 | 15 | 16 | play(2)} 20 | > 21 | 22 | 23 | 24 | play(3)} 28 | > 29 | 35 | 36 | 37 | ); 38 | } 39 | 40 | const styles = StyleSheet.create({ 41 | actions: { 42 | height: 100, 43 | flexDirection: "row", 44 | justifyContent: "space-around", 45 | alignItems: "center", 46 | }, 47 | actionButton: { 48 | width: 64, 49 | height: 64, 50 | justifyContent: "center", 51 | alignItems: "center", 52 | backgroundColor: "#f9d835", 53 | borderRadius: 32, 54 | }, 55 | }); 56 | -------------------------------------------------------------------------------- /examples/8-stopwatch/Control.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { StyleSheet, Text, TouchableOpacity, View } from "react-native"; 3 | 4 | function Control({ isRunning, handleLeftButtonPress, handleRightButtonPress }) { 5 | return ( 6 | <> 7 | 14 | 15 | 16 | {isRunning ? "Step" : "Reset"} 17 | 18 | 19 | 20 | 21 | 28 | 29 | 30 | {isRunning ? "Stop" : "Start"} 31 | 32 | 33 | 34 | 35 | ); 36 | } 37 | 38 | const CENTER = { 39 | justifyContent: "center", 40 | alignItems: "center", 41 | }; 42 | 43 | const styles = StyleSheet.create({ 44 | controlButtonBorder: { 45 | ...CENTER, 46 | width: 70, 47 | height: 70, 48 | borderRadius: 70, 49 | }, 50 | controlButton: { 51 | ...CENTER, 52 | width: 65, 53 | height: 65, 54 | borderRadius: 65, 55 | borderColor: "#000", 56 | borderWidth: 1, 57 | }, 58 | }); 59 | 60 | export default React.memo(Control); 61 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-expo-examples", 3 | "version": "1.0.0", 4 | "author": "Robin Huy", 5 | "license": "Apache-2.0", 6 | "main": "expo/AppEntry.js", 7 | "scripts": { 8 | "start": "expo start", 9 | "android": "expo start --android", 10 | "ios": "expo start --ios", 11 | "web": "expo start --web" 12 | }, 13 | "dependencies": { 14 | "@react-native-community/masked-view": "^0.1.11", 15 | "@react-native-community/slider": "4.5.2", 16 | "@react-navigation/bottom-tabs": "^6.5.0", 17 | "@react-navigation/native": "^6.1.0", 18 | "@react-navigation/stack": "^6.3.8", 19 | "date-fns": "^2.29.3", 20 | "expo": "^51.0.24", 21 | "expo-av": "^14.0.6", 22 | "expo-barcode-scanner": "~13.0.1", 23 | "expo-router": "^3.5.20", 24 | "expo-status-bar": "~1.12.1", 25 | "expo-updates": "^0.25.21", 26 | "formik": "^2.2.9", 27 | "lodash": "^4.17.21", 28 | "react": "18.2.0", 29 | "react-dom": "18.2.0", 30 | "react-native": "0.74.3", 31 | "react-native-animatable": "^1.3.3", 32 | "react-native-elements": "^3.4.2", 33 | "react-native-gesture-handler": "~2.16.1", 34 | "react-native-keyboard-aware-scroll-view": "^0.9.5", 35 | "react-native-modal": "^13.0.1", 36 | "react-native-progress": "^5.0.0", 37 | "react-native-reanimated": "~3.10.1", 38 | "react-native-safe-area-context": "4.10.5", 39 | "react-native-screens": "3.31.1", 40 | "react-native-web": "~0.19.6", 41 | "typescript": "~5.3.3", 42 | "yup": "^0.32.11" 43 | }, 44 | "devDependencies": { 45 | "@babel/core": "^7.24.7", 46 | "babel-preset-expo": "^11.0.7", 47 | "eslint": "^8.57.0", 48 | "eslint-config-expo": "^7.0.0" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /examples/9-bmi-calculator/components/HeightSelection.js: -------------------------------------------------------------------------------- 1 | import Slider from "@react-native-community/slider"; 2 | import React from "react"; 3 | import { Platform, StyleSheet, Text, View } from "react-native"; 4 | import sliderThumbImage from "../assets/slider-thumb-image.png"; 5 | import { BOX, TEXT_LABEL, TEXT_VALUE } from "../style"; 6 | 7 | const MIN_HEIGHT = 50; 8 | const MAX_HEIGHT = 250; 9 | 10 | function HeightSelection({ style, height, setHeight }) { 11 | return ( 12 | 13 | 14 | HEIGHT 15 | 16 | 17 | {height} 18 | cm 19 | 20 | 21 | {/* https://github.com/react-native-community/react-native-slider */} 22 | setHeight(Math.round(value))} 30 | value={height} 31 | /> 32 | 33 | 34 | ); 35 | } 36 | 37 | const styles = StyleSheet.create({ 38 | heightSelection: { 39 | ...BOX, 40 | marginVertical: 10, 41 | }, 42 | label: { 43 | ...TEXT_LABEL, 44 | }, 45 | value: { 46 | ...TEXT_VALUE, 47 | }, 48 | unit: { 49 | fontSize: 16, 50 | }, 51 | slider: { 52 | width: "100%", 53 | height: 40, 54 | transform: Platform.OS === "android" ? [{ scale: 1.1 }] : [], 55 | }, 56 | }); 57 | 58 | export default React.memo(HeightSelection); 59 | -------------------------------------------------------------------------------- /examples/5-instagram-feed/data.js: -------------------------------------------------------------------------------- 1 | export const profile = { 2 | avatar: require("./assets/avatar.png"), 3 | }; 4 | 5 | export const stories = [ 6 | { 7 | id: 1, 8 | avatar: require("./assets/avatar1.jpg"), 9 | name: "5.min.craft", 10 | isSeen: false, 11 | }, 12 | { 13 | id: 2, 14 | avatar: require("./assets/avatar2.jpg"), 15 | name: "teammonsterbox", 16 | isSeen: false, 17 | }, 18 | { 19 | id: 3, 20 | avatar: require("./assets/avatar3.jpg"), 21 | name: "thangflycomicsoffical", 22 | isSeen: true, 23 | }, 24 | { 25 | id: 4, 26 | avatar: require("./assets/avatar4.jpg"), 27 | name: "other__perspectives", 28 | isSeen: true, 29 | }, 30 | ]; 31 | 32 | export const articles = [ 33 | { 34 | id: 1, 35 | avatar: require("./assets/avatar1.jpg"), 36 | name: "5.min.craft", 37 | image: require("./assets/img1.jpg"), 38 | likeCount: "23", 39 | date: "1 hour ago", 40 | }, 41 | { 42 | id: 2, 43 | avatar: require("./assets/avatar1.jpg"), 44 | name: "5.min.craft", 45 | image: require("./assets/img2.jpg"), 46 | likeCount: "46", 47 | date: "3 hours ago", 48 | }, 49 | { 50 | id: 3, 51 | avatar: require("./assets/avatar3.jpg"), 52 | name: "thangflycomicsoffical", 53 | image: require("./assets/img3.jpg"), 54 | likeCount: "72", 55 | date: "8 hours ago", 56 | }, 57 | { 58 | id: 4, 59 | avatar: require("./assets/avatar2.jpg"), 60 | name: "teammonsterbox", 61 | image: require("./assets/img4.jpg"), 62 | likeCount: "19", 63 | date: "1 day ago", 64 | }, 65 | { 66 | id: 5, 67 | avatar: require("./assets/avatar2.jpg"), 68 | name: "teammonsterbox", 69 | image: require("./assets/img5.jpg"), 70 | likeCount: "12", 71 | date: "2 days ago", 72 | }, 73 | ]; 74 | -------------------------------------------------------------------------------- /examples/5-instagram-feed/InstagramFeed.js: -------------------------------------------------------------------------------- 1 | import Constants from "expo-constants"; 2 | import { StatusBar } from "expo-status-bar"; 3 | import React from "react"; 4 | import { FlatList, SafeAreaView, StyleSheet, View } from "react-native"; 5 | import Article from "./components/Article"; 6 | import Header from "./components/Header"; 7 | import Stories from "./components/Stories"; 8 | import { articles } from "./data"; 9 | 10 | export default function Instagram() { 11 | const renderItem = ({ item }) =>
; 12 | const renderHeader = () => ( 13 | 14 | 15 | 16 | ); 17 | const keyExtractor = (item) => item.id.toString(); 18 | 19 | return ( 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | {/* https://reactnative.dev/docs/flatlist */} 28 | 35 | 36 | ); 37 | } 38 | 39 | const BORDER_BOTTOM = { 40 | borderBottomWidth: 1, 41 | borderBottomColor: "#dbdbdb", 42 | }; 43 | 44 | const styles = StyleSheet.create({ 45 | container: { 46 | flex: 1, 47 | paddingTop: Constants.statusBarHeight, 48 | }, 49 | header: { 50 | ...BORDER_BOTTOM, 51 | flexDirection: "row", 52 | justifyContent: "space-between", 53 | alignItems: "center", 54 | paddingHorizontal: 16, 55 | height: 44, 56 | }, 57 | stories: { 58 | ...BORDER_BOTTOM, 59 | height: 104, 60 | paddingVertical: 10, 61 | paddingLeft: 8, 62 | backgroundColor: "#fafafa", 63 | }, 64 | }); 65 | -------------------------------------------------------------------------------- /examples/6-rock-paper-scissors/DisplayResult.js: -------------------------------------------------------------------------------- 1 | import { FontAwesome5 } from "@expo/vector-icons"; 2 | import React from "react"; 3 | import { StyleSheet, Text, View } from "react-native"; 4 | 5 | const ICONS = ["hand-rock", "hand-paper", "hand-scissors"]; 6 | 7 | export default function DisplayResult({ userChoice, computerChoice }) { 8 | return ( 9 | <> 10 | 11 | 18 | You 19 | 20 | 21 | 22 | 31 | Computer 32 | 33 | 34 | ); 35 | } 36 | 37 | const styles = StyleSheet.create({ 38 | column: { 39 | flex: 1, 40 | justifyContent: "center", 41 | alignItems: "center", 42 | }, 43 | playerName: { 44 | color: "#373737", 45 | fontSize: 16, 46 | marginTop: 16, 47 | }, 48 | leftIcon: { 49 | transform: [{ rotateZ: "80deg" }], 50 | }, 51 | scissorsLeftIcon: { 52 | transform: [{ rotateZ: "180deg" }, { rotateX: "180deg" }], 53 | }, 54 | rightIcon: { 55 | transform: [{ rotateZ: "-80deg" }, { rotateY: "180deg" }], 56 | }, 57 | scissorsRightIcon: { 58 | transform: [ 59 | { rotateZ: "180deg" }, 60 | { rotateY: "180deg" }, 61 | { rotateX: "180deg" }, 62 | ], 63 | }, 64 | }); 65 | -------------------------------------------------------------------------------- /examples/11-news/Article.js: -------------------------------------------------------------------------------- 1 | import formatDistanceToNow from "date-fns/formatDistanceToNow"; 2 | import React from "react"; 3 | import { 4 | Alert, 5 | Image, 6 | Linking, 7 | StyleSheet, 8 | Text, 9 | TouchableOpacity, 10 | View, 11 | } from "react-native"; 12 | 13 | export default function Article({ item }) { 14 | const openLink = () => { 15 | const url = item.url; 16 | 17 | // https://reactnative.dev/docs/linking 18 | Linking.canOpenURL(url).then((supported) => { 19 | if (supported) { 20 | Linking.openURL(url); 21 | } else { 22 | Alert.alert("Broken Link!"); 23 | } 24 | }); 25 | }; 26 | 27 | const publishedFromNow = formatDistanceToNow(new Date(item.publishedAt)); 28 | 29 | return ( 30 | 31 | {/* Caching image for better performance: https://github.com/DylanVann/react-native-fast-image */} 32 | 33 | 34 | 35 | 36 | 37 | {item.title} 38 | 39 | 40 | 41 | {publishedFromNow} 42 | 43 | 44 | ); 45 | } 46 | 47 | const styles = StyleSheet.create({ 48 | article: { 49 | flexDirection: "row", 50 | paddingVertical: 15, 51 | }, 52 | articleImage: { 53 | width: 150, 54 | height: 85, 55 | resizeMode: "contain", 56 | marginRight: 15, 57 | }, 58 | articleTitle: { 59 | fontSize: 18, 60 | fontWeight: "bold", 61 | marginBottom: 10, 62 | }, 63 | articleDescription: { 64 | fontSize: 16, 65 | marginBottom: 10, 66 | }, 67 | articlePublishedAt: { 68 | fontSize: 14, 69 | }, 70 | }); 71 | -------------------------------------------------------------------------------- /examples/7-scan-qr-code/ScannerView.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { StyleSheet, View } from "react-native"; 3 | import * as Animatable from "react-native-animatable"; 4 | 5 | export default function ScannerView({ scanned }) { 6 | return ( 7 | // https://github.com/oblador/react-native-animatable 8 | 13 | 14 | 15 | 16 | 17 | 18 | ); 19 | } 20 | 21 | const BORDER = { 22 | position: "absolute", 23 | borderColor: "#fff", 24 | width: 55, 25 | height: 55, 26 | }; 27 | const BORDER_WIDTH = 10; 28 | const BORDER_RADIUS = 35; 29 | 30 | const styles = StyleSheet.create({ 31 | scannerView: { 32 | width: 220, 33 | height: 220, 34 | }, 35 | borderTopLeft: { 36 | ...BORDER, 37 | top: 0, 38 | left: 0, 39 | borderTopLeftRadius: BORDER_RADIUS, 40 | borderTopWidth: BORDER_WIDTH, 41 | borderLeftWidth: BORDER_WIDTH, 42 | }, 43 | borderTopRight: { 44 | ...BORDER, 45 | top: 0, 46 | right: 0, 47 | borderTopRightRadius: BORDER_RADIUS, 48 | borderTopWidth: BORDER_WIDTH, 49 | borderRightWidth: BORDER_WIDTH, 50 | }, 51 | borderBottomLeft: { 52 | ...BORDER, 53 | bottom: 0, 54 | left: 0, 55 | borderBottomLeftRadius: BORDER_RADIUS, 56 | borderBottomWidth: BORDER_WIDTH, 57 | borderLeftWidth: BORDER_WIDTH, 58 | }, 59 | borderBottomRight: { 60 | ...BORDER, 61 | bottom: 0, 62 | right: 0, 63 | borderBottomRightRadius: BORDER_RADIUS, 64 | borderBottomWidth: BORDER_WIDTH, 65 | borderRightWidth: BORDER_WIDTH, 66 | }, 67 | }); 68 | -------------------------------------------------------------------------------- /examples/3-the-light/1.TheLight.js: -------------------------------------------------------------------------------- 1 | import Constants from "expo-constants"; 2 | import { StatusBar } from "expo-status-bar"; 3 | import React, { useState } from "react"; 4 | import { 5 | Dimensions, 6 | Image, 7 | Platform, 8 | SafeAreaView, 9 | StyleSheet, 10 | Switch, 11 | } from "react-native"; 12 | import bulbOff from "./assets/bulb-off.jpg"; 13 | import bulbOn from "./assets/bulb-on.jpg"; 14 | 15 | export default function TheLight() { 16 | // https://reactjs.org/docs/hooks-reference.html#usestate 17 | const [isEnabled, setIsEnabled] = useState(false); 18 | const toggleSwitch = () => setIsEnabled((previousState) => !previousState); 19 | 20 | return ( 21 | 22 | 23 | 24 | 29 | 30 | {/* https://reactnative.dev/docs/switch */} 31 | 38 | 39 | ); 40 | } 41 | 42 | // https://reactnative.dev/docs/dimensions 43 | const screenHeight = Dimensions.get("window").height; 44 | 45 | const styles = StyleSheet.create({ 46 | container: { 47 | flex: 1, 48 | backgroundColor: "black", 49 | paddingTop: Constants.statusBarHeight, 50 | }, 51 | image: { 52 | maxWidth: "100%", 53 | maxHeight: screenHeight - Constants.statusBarHeight - 150, 54 | resizeMode: "contain", 55 | marginBottom: 20, 56 | }, 57 | switch: { 58 | alignSelf: "center", 59 | // https://reactnative.dev/docs/transforms 60 | // https://reactnative.dev/docs/platform-specific-code 61 | transform: Platform.OS === "android" ? [{ scale: 1.5 }] : [], 62 | }, 63 | }); 64 | -------------------------------------------------------------------------------- /examples/5-instagram-feed/components/Story.js: -------------------------------------------------------------------------------- 1 | import { Feather } from "@expo/vector-icons"; 2 | import React from "react"; 3 | import { Image, StyleSheet, Text, TouchableOpacity, View } from "react-native"; 4 | 5 | export default function Story({ avatar, name, isCreateStory = false, isSeen }) { 6 | return ( 7 | 8 | 9 | 21 | 22 | 23 | {isCreateStory && ( 24 | 25 | 26 | 27 | )} 28 | 29 | 30 | 31 | {name} 32 | 33 | 34 | 35 | ); 36 | } 37 | 38 | const styles = StyleSheet.create({ 39 | user: { 40 | width: 80, 41 | paddingHorizontal: 4, 42 | }, 43 | avatarBorder: { 44 | width: 56, 45 | height: 56, 46 | borderRadius: 28, 47 | borderWidth: 1, 48 | margin: 4, 49 | marginBottom: 8, 50 | justifyContent: "center", 51 | alignItems: "center", 52 | }, 53 | avatar: { 54 | width: 50, 55 | height: 50, 56 | borderRadius: 25, 57 | }, 58 | plusIcon: { 59 | position: "absolute", 60 | right: 0, 61 | bottom: 0, 62 | width: 18, 63 | height: 18, 64 | borderRadius: 10, 65 | overflow: "hidden", 66 | justifyContent: "center", 67 | alignItems: "center", 68 | backgroundColor: "#3e95f6", 69 | }, 70 | name: { 71 | textAlign: "center", 72 | fontSize: 10, 73 | lineHeight: 14, 74 | color: "#262626", 75 | maxWidth: 64, 76 | }, 77 | }); 78 | -------------------------------------------------------------------------------- /App.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import { 3 | StyleSheet, 4 | SafeAreaView, 5 | ScrollView, 6 | View, 7 | BackHandler, 8 | } from "react-native"; 9 | import { Text, ListItem } from "react-native-elements"; 10 | import Constants from "expo-constants"; 11 | import { EXAMPLE_LIST } from "./example-list"; 12 | 13 | export default function App() { 14 | const [exampleIndex, setExampleIndex] = useState(null); 15 | 16 | // Handle when user press Hardware Back Button 17 | useEffect(() => { 18 | const backAction = () => { 19 | // Go back to Example List 20 | if (exampleIndex !== null) { 21 | setExampleIndex(null); 22 | } 23 | // Exit app if user currently in Example List 24 | else { 25 | BackHandler.exitApp(); 26 | } 27 | 28 | return true; 29 | }; 30 | 31 | // https://reactnative.dev/docs/backhandler 32 | const backHandler = BackHandler.addEventListener( 33 | "hardwareBackPress", 34 | backAction 35 | ); 36 | 37 | return () => backHandler.remove(); 38 | }, [exampleIndex]); 39 | 40 | if (exampleIndex !== null) return EXAMPLE_LIST[exampleIndex].component; 41 | 42 | return ( 43 | 44 | 45 | React Native Expo Examples 46 | 47 | 48 | 49 | {EXAMPLE_LIST.map((l, i) => ( 50 | setExampleIndex(i)}> 51 | 52 | Level {l.level} 53 | 54 | 55 | 56 | {l.name} 57 | 58 | 59 | ))} 60 | 61 | 62 | ); 63 | } 64 | 65 | const styles = StyleSheet.create({ 66 | container: { 67 | flex: 1, 68 | paddingTop: Constants.statusBarHeight, 69 | }, 70 | heading: { 71 | textAlign: "center", 72 | padding: 12, 73 | }, 74 | title: { 75 | fontWeight: "bold", 76 | }, 77 | }); 78 | -------------------------------------------------------------------------------- /examples/9-bmi-calculator/components/ResultModal.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Modal, SafeAreaView, StyleSheet, Text, View } from "react-native"; 3 | import { BOX, TEXT } from "../style"; 4 | import Button from "./Button"; 5 | 6 | const GOOD_STATUS_COLOR = "#7ac79d"; 7 | const BAD_STATUS_COLOR = "#f5ac40"; 8 | 9 | function ResultModal({ 10 | modalVisible, 11 | bmiPoint, 12 | bmiStatus, 13 | bmiInterpretation, 14 | onModalConfirm, 15 | }) { 16 | return ( 17 | // https://reactnative.dev/docs/modal 18 | 19 | 20 | 21 | Your Result 22 | 23 | 24 | 35 | {bmiStatus} 36 | 37 | 38 | {bmiPoint} 39 | 40 | 41 | {bmiInterpretation} 42 | 43 | 44 | 45 |