페이징을 위해 외부 라이브러리 사용
react-navigation 공식 문서
설치
yarn add @react-navigation/native
expo install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view
설치
yarn add @react-navigation/stack
const Stack = createStackNavigator();
const StackNavigator = () => {
return (
<Stack.Navigator
screenOptions={{
headerStyle: {
backgroundColor: "black",
borderBottomColor: "black",
shadowColor: "black",
height: 100,
},
headerTintColor: "white",
headerBackTitleVisible: false,
}}>
<Stack.Screen name="SignInPage" component={SignInPage} />
<Stack.Screen name="SignUpPage" component={SignUpPage} />
<Stack.Screen name="MainPage" component={MainPage} />
<Stack.Screen name="DetailPage" component={DetailPage} />
<Stack.Screen name="AddPage" component={AddPage} />
<Stack.Screen name="MyPage" component={MyPage} />
</Stack.Navigator>
);
};
export default StackNavigator;
import React, { useEffect, useState } from "react";
import { StyleSheet } from "react-native";
import { NavigationContainer } from "@react-navigation/native";
import StackNavigator from "./navigations/StackNavigator";
export default function App() {
return (
<NavigationContainer>
<StackNavigator />
</NavigationContainer>
);
}
const styles = StyleSheet.create({
contianer: {
flex: 1,
},
});
//navigation 객체가 가지고 있는 두 함수(setOptions와 navigate)
export default function SignUpPage({ navigation, route }) {}
//해당 페이지의 제목을 설정할 수 있음
navigation.setOptions({
title: "wegram",
});
//Stack.screen에서 name 속성으로 정해준 이름을 지정해주면 해당 페이지로 이동하는 함수
navigation.navigate("DetailPage");
//name 속성을 전달해주고, 두 번째 인자로 딕셔너리 데이터를 전달해주면, Detail 페이지에서
//두번째 인자로 전달된 딕셔너리 데이터를 route 딕셔너리로 로 받을 수 있음
navigation.navigate("DetailPage", {
title: title,
});
//전달받은 데이터를 받는 route 딕셔너리
//비구조 할당 방식으로 route에 params 객체 키로 연결되어 전달되는 데이터를 꺼내 사용
//navigate 함수로 전달되는 딕셔너리 데이터는 다음과 같은 모습이기 때문
/*
{
route : {
params :{
title:title
}
}
}
*/
const { title } = route.params;
페이지 이동
import React from "react";
import { StyleSheet, View, Text, TouchableOpacity } from "react-native";
export default function SignInPage({ navigation }) {
const goSignUp = () => {
navigation.navigate("SignUpPage");
};
return (
<View style={styles.container}>
<Text>SignInPage</Text>
<TouchableOpacity onPress={goSignUp}>
<Text>Sign Up</Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
});
페이지 이동 시 데이터 전송
route의 params 딕셔너리에서 값을 꺼내 사용
이전 페이지에서 넘긴 데이터들은 route.params에 딕셔너리 형태로 존재
SignInPage에서 SignUpPage로 title 데이터 값 전송
SignInPage
const goSignUp = () => {
navigation.navigate("SignUpPage", { title: "from SignInPage" });
};
SignUpPage
export default function SignUpPage({ route }) {
return (
<View style={styles.container}>
<Text>SignUpPage</Text>
<Text>{route.params.title}</Text>
</View>
);
}
//전달받은 데이터를 받는 route 딕셔너리
//비구조 할당 방식으로 route에 params 객체 키로 연결되어 전달되는 데이터를 꺼내 사용
//navigate 함수로 전달되는 딕셔너리 데이터는 다음과 같은 모습이기 때문
/*
{
route : {
params :{
title:title
}
}
}
*/
const { title } = route.params;
설치
yarn add @react-navigation/bottom-tabs
import React from "react";
import { Platform } from "react-native";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import MainPage from "../pages/MainPage";
import MyPage from "../pages/MyPage";
import AddPage from "../pages/AddPage";
const Tabs = createBottomTabNavigator();
const TabNavigator = ({ navigation, route }) => {
return (
<Tabs.Navigator
tabBarOptions={{
showLabel: true,
style: {
backgroundColor: "white",
borderTopColor: "lightgray",
height: 40,
fontSize: 10,
},
activeTintColor: "tomato",
inactiveTintColor: "gray",
}}>
<Tabs.Screen name="MainPage" component={MainPage} />
<Tabs.Screen name="MyPage" component={MyPage} />
<Tabs.Screen name="AddPage" component={AddPage} />
</Tabs.Navigator>
);
};
export default TabNavigator;
import React from "react";
import { createStackNavigator } from "@react-navigation/stack";
import SignInPage from "../pages/SignInPage";
import SignUpPage from "../pages/SignUpPage";
import DetailPage from "../pages/DetailPage";
import TabNavigator from "./TabNavigator";
const Stack = createStackNavigator();
const StackNavigator = () => {
return (
<Stack.Navigator
screenOptions={{
headerShown: false,
}}>
<Stack.Screen name="TabNavigator" component={TabNavigator} />
<Stack.Screen name="SignInPage" component={SignInPage} />
<Stack.Screen name="SignUpPage" component={SignUpPage} />
<Stack.Screen name="DetailPage" component={DetailPage} />
</Stack.Navigator>
);
};
export default StackNavigator;
activeTintColor
inactiveTintColor
탭에 아이콘 삽입 (라벨 숨기기)
import React from "react";
import { Platform } from "react-native";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import { Ionicons } from "@expo/vector-icons";
import MainPage from "../pages/MainPage";
import MyPage from "../pages/MyPage";
import AddPage from "../pages/AddPage";
const Tabs = createBottomTabNavigator();
const TabNavigator = ({ navigation, route }) => {
return (
<Tabs.Navigator
screenOptions={({ route }) => ({
headerShown: false,
tabBarIcon: ({ focused }) => {
let iconName = Platform.OS === "ios" ? "ios-" : "md-";
if (route.name === "MainPage") {
iconName += "list";
} else if (route.name === "AddPage") {
iconName += "apps-outline";
} else if (route.name === "MyPage") {
iconName += "person";
}
return (
<Ionicons
name={iconName}
color={focused ? "hotpink" : "grey"}
size={26}
/>
);
},
})}
tabBarOptions={{
showLabel: false,
style: {
backgroundColor: "white",
borderTopColor: "lightgray",
height: 40,
fontSize: 10,
},
activeTintColor: "tomato",
inactiveTintColor: "gray",
}}>
<Tabs.Screen name="MainPage" component={MainPage} />
<Tabs.Screen name="MyPage" component={MyPage} />
<Tabs.Screen name="AddPage" component={AddPage} />
</Tabs.Navigator>
);
};
export default TabNavigator;
screenOptions={({ route }) => ({ })
에서 route 부분은 어떤 페이지를 현재 사용자가 보고 있는지에 대한 정보tabBarIcon: ({ focused }) => {}})
부분은 특정 탭을 눌렀을 때, 즉 포커싱(focused) 되었을때 어떠한 아이콘을 보여줄지 결정import { Ionicons } from '@expo/vector-icons';
은 기기들 마다 제공되는 아이콘이 다르기때문에 iOS인지 안드로이드인지 구별한 후 적절히 이름 결정ios-
가 붙고 안드로이드에는 md-
특정 탭 누를때 이벤트 팝업 / 데이터 전송 시
import React, { useEffect } from "react";
import { StyleSheet, View, Text, Alert } from "react-native";
export default function MainPage({ navigation }) {
useEffect(() => {
const unsubscribe = navigation.addListener("focus", (e) => {
Alert.alert("Main Page!");
});
return unsubscribe;
}, [navigation]);
return (
<View>
<Text>MainPage</Text>
</View>
);
}
const styles = StyleSheet.create({});
useEffect(() => {
const unsubscrbie = navigation.addListener('focus', (e) => {
Alert.alert('메인페이지에 들어왔군요!');
});
}, [navigation]);
const unsubscribe
에 팝업 기능을 담아뒀기 때문에 팝업이 한 번만 실행되기 위해서 unsubscribe를 return에 두어 정리return unsubscrbie;
NativeBase
설치
yarn add native-base@2 --save
폰트 도구 설치
expo install expo-font
App.jsx
import React, { useEffect, useState } from "react";
import { StyleSheet } from "react-native";
import { NavigationContainer } from "@react-navigation/native";
import StackNavigator from "./navigations/StackNavigator";
import * as Font from "expo-font";
import { Ionicons } from "@expo/vector-icons";
import Loading from "./pages/Loading";
export default function App() {
const [ready, setReady] = useState(false);
const loadFont = () => {
setTimeout(async () => {
await Font.loadAsync({
Roboto: require("native-base/Fonts/Roboto.ttf"),
Roboto_medium: require("native-base/Fonts/Roboto_medium.ttf"),
...Ionicons.font,
});
await setReady(true);
}, 1000);
};
useEffect(() => {
loadFont();
}, []);
return ready ? (
<NavigationContainer>
<StackNavigator />
</NavigationContainer>
) : (
<Loading />
);
}
const styles = StyleSheet.create({
contianer: {
flex: 1,
},
});
Roboto
Roboto는 Google에서 모바일 운영 체제 Android의 시스템 글꼴로 개발 한 네오 그로테스크 한 산세 리프 서체 제품군으로 2011 년 Android 4.0 "Ice Cream Sandwich"용으로 출시
const loadFont = () => {
setTimeout(async () => {
await Font.loadAsync({
Roboto: require("native-base/Fonts/Roboto.ttf"),
Roboto_medium: require("native-base/Fonts/Roboto_medium.ttf"),
...Ionicons.font,
});
await setReady(true);
}, 1000);
};
import React, { Component } from "react";
import { Container, Header } from "native-base";
import { Col, Row, Grid } from "react-native-easy-grid";
export default function SignInPage() {
return (
<Container>
<Header />
<Grid>
<Col size={2} style={{ backgroundColor: "#635DB7", height: 200 }}></Col>
<Col size={1} style={{ backgroundColor: "#00CE9F", height: 200 }}></Col>
</Grid>
</Container>
);
}
Form : React Native의 View
Item : React Native의 TouchableOpacity
Input : React Native의 TextInput
Label : React Native의 Text
import React, { Component } from "react";
import { StyleSheet, ImageBackground } from "react-native";
import {
Container,
Content,
Text,
Form,
Item,
Input,
Label,
Button,
} from "native-base";
const bImage = require("../assets/background.png");
export default function SignInPage({ navigation }) {
const goSignUp = () => {
navigation.navigate("SignUpPage");
};
return (
<Container style={styles.container}>
<ImageBackground source={bImage} style={styles.backgroundImage}>
<Content contentContainerStyle={styles.content} scrollEnabled={false}>
<Text style={styles.title}>
<Text style={styles.highlite}>we</Text>gram
</Text>
<Form style={styles.form}>
<Item floatingLabel last>
<Label style={styles.label}>E-mail</Label>
<Input style={styles.input} />
</Item>
<Item floatingLabel last>
<Label style={styles.label}>Password</Label>
<Input style={styles.input} />
</Item>
</Form>
<Button full style={styles.emailSignIn}>
<Text>E-mail LogIn</Text>
</Button>
<Button full style={styles.emailSignUp} onPress={goSignUp}>
<Text style={{ color: "white" }}>SignUp</Text>
</Button>
</Content>
</ImageBackground>
</Container>
);
}
import React from "react";
import { StyleSheet } from "react-native";
import { Item, Input, Label } from "native-base";
export default function ItemInput({ title }) {
return (
<Item floatingLabel last>
<Label style={styles.label}>{title}</Label>
<Input style={styles.input} />
</Item>
);
}
import React from "react";
import { StyleSheet, ImageBackground } from "react-native";
import {
Container,
Content,
Text,
Form,
Item,
Input,
Label,
Button,
Header,
Left,
Icon,
Body,
Right,
} from "native-base";
import ItemInput from "../components/ItemInput";
const bImage = require("../assets/background.png");
export default function SignUpPage({ navigation }) {
return (
<Container style={styles.container}>
<ImageBackground source={bImage} style={styles.backgroundImage}>
<Header transparent>
<Left>
<Button
transparent
onPress={() => {
navigation.goBack();
}}>
<Icon name="arrow-back" style={{ color: "white" }} />
</Button>
</Left>
<Body />
<Right />
</Header>
<Content contentContainerStyle={styles.content} scrollEnabled={false}>
<Text style={styles.title}>
<Text style={styles.highlite}>we</Text>gram signup
</Text>
<Form style={styles.form}>
<ItemInput title={"nickname"} />
<ItemInput title={"E-mail"} />
<ItemInput title={"Password"} />
<ItemInput title={"Password check"} />
</Form>
<Button full style={styles.emailSignUp}>
<Text>Register</Text>
</Button>
</Content>
</ImageBackground>
</Container>
);
}
<Header transparent>
react-native-image-blur-loading
설치
yarn add react-native-image-blur-loading
import React from 'react';
import { StyleSheet, TouchableOpacity } from 'react-native';
import {} from 'react-native-easy-grid';
import { Card, CardItem, Col, Grid, Icon, Text } from 'native-base';
import ImageBlurLoading from 'react-native-image-blur-loading';
const image = require('../assets/background2.png');
const logo = require('../assets/logo.png');
export default function CardComponent({ navigation }) {
return (
<TouchableOpacity
onPress={() => {
navigation.navigate('DetailPage');
}}
style={styles.container}
>
<Card style={styles.card} transparent>
<CardItem transparent>
<ImageBlurLoading
withIndicator
thumbnailSource={image}
source={image}
style={styles.image}
/>
</CardItem>
...
<View style={{ marginTop: -20 }}>
{data.diary.map((content, i) => {
return <CardComponent content={content} key={i} navigation={navigation} />;
})}
</View>
export default function CardComponent({ navigation, content }) {
return (
<TouchableOpacity
onPress={() => {
navigation.navigate('DetailPage');
}}
style={styles.container}
>
<Card style={styles.card} transparent>
<CardItem transparent>
<ImageBlurLoading
withIndicator
thumbnailSource={{ uri: content.image }}
source={{ uri: content.image }}
style={styles.image}
/>
</CardItem>
...
react-native-animatable 설치
yarn add react-native-animatable
import * as Animatable from 'react-native-animatable';
const data = require('../data.json');
export default function MainPage({ navigation }) {
return (
<Container>
<HeaderComponent />
<Content>
<Animatable.View
animation="pulse"
easing="ease-out"
iterationCount={'infinite'}
direction="alternate"
>
<Grid style={styles.banner}>
<Col size={1} style={{ padding: 20 }}>
<Icon name="paper-plane" style={{ color: 'orange' }} />
</Col>
<Col size={6} style={{ padding: 15 }}>
<Text>이야기 하고 싶은 친구들에게</Text>
<Text style={{ fontWeight: 'bold' }}>wegram을 전하세요</Text>
</Col>
</Grid>
</Animatable.View>
...