저번주차처럼 쓰니까 개발일지 작성 시간이 어마무시하다... 이제 아는 것은 간단히 쓰고 새로 안 내용 위주로 작성하려고 한다. 그리고 문어체보단 이런 구어체가 편하니 이렇게 작성하는 걸로...
React Native가 JavaScript 기반인건 알겠는데, 사실 순수 React Native로만으로는 크로스 플랫폼 개발을 할 때 기기의 센서를 다루는 부분이라던가 더 많은 기능을 사용하기 위해서는 Java나 Swift를 알아야한다고 한다. 그래서 진짜 JavaScript만으로 개발을 하기 위해서 사용하는 플랫폼이 Expo라고한다.
Expo에서는 개발을 위해 여러가지 기능들을 제공하는데 그 중 개발 앱 테스트를 위해 제공하는 클라이언트 앱이 엄청 마음에 들었다. 코드를 작성하고 저장하면 pycharm처럼 바로바로 핸드폰 화면에 적용이 되어서 엄청 편리했다! (Android Studio에서는 계속 액티비티 리프레쉬 하느라 애 먹었는데 ㅠ)
Expo를 통해서 앱 개발을 하려면 이것저것 설치할 것도 있지만 그렇게 큰 어려움은 없었다. 설치에 필요한 것이나 과정들은 길기 때문에 생략!
vscode 터미널 토글 단축키 - Ctrl + ~ (사실 백틱 키인데 마크업으로 쓰다보니...ㅠ)
아래부터는 터미널 명령어이다.
expo init - 현재 폴더에 expo를 기반한 기본 프로젝트를 생성하는 명령어이다.
expo start - 앱 테스트 시작 시 명령어, 터미널에 나오는 QR코드를 클라이언트 앱으로 찍으면 파일을 저장할 때마다 실시간으로 화면에 코드 변경이 반영된다
Ctrl + C - 종료 단축키. 이거 몰라서 조금 (마음이) 불편했음. 왠지 개발 안 할 때나 끌 때 X 눌러서 창 꺼 버리면 찝찝함ㅎ
앱이 가지는 기본 정보들을 설정하는 파일
//우리가 리액트, 리액트 네이티브, 엑스포 라이브러리에서 꺼내 사용할 기능들을
//이렇게 앞으로도 상단에 선언한다음 가져다 사용합니다.
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
//App.js는 결국 App 함수를 내보내기 하고 있는 자바스크립트 파일입니다.
//이 함수는 무언가?를 반환하고 있는데 결국 화면을 반환하고 있습니다.
export default function App() {
//화면을 반환합니다.
//HTML 태그 같이 생긴 이 문법은 JSX라 불리우며 실제 화면을 그리는 문법입니다,
//이번 강의에서 자세히 다룹니다
return (
<View style={styles.container}>
<Text>Open up App.js to start working on your app!</Text>
<StatusBar style="auto" />
</View>
);
}
// styles 변수 이름 답게 화면을 그려주는,
//더 자세히는 JSX문법을 꾸며주는 내용을 담고 있습니다.
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
대충 보니까 크게 나누면
importexport default function App()const styles = Style.Sheet.create()이렇게 3개로 나눌 수 있는듯 하다.
importpublic void onCreate(Bundle savedInstanceState) {} 정도 되려나. 앱의 화면을 그려주는 부분이라고 한다. 이걸 JSX문법으로 그려저 준비된 화면을 반환한다고 표현하고, 이러한 행위, 동작을 렌더링(rendering)이라고 부른다.const styles = Style.Sheet.create()위와 같이 이해하고 코딩을 좀 해봤는데 문제는 딱히 없는거 같다. 한가지 언어를 배워놓으면 다른거 배울 때도 편하다는게 이런거 같다.
function App() 안의 내용을 보면 HTML태그처럼 <View>가 보이는데, 여기서도 태그라고 부른다. 그리고 닫는 태그(</View>)까지 포함시켜 온전히 화면의 한 영역을 구성할때 엘리먼트라고 부른다.
JSX의 기본 문법은 아래와 같다.
<View>나 <Text>는 우리가 만든 태그가 아니고 이미 라이브러리에 존재하는 태그들이다. 모든 태그를 가져와서 요리조리 섞어서 사용해야 된다는 것이다.<Image /> 처럼 자체적으로 닫는 태그가 있는가 하면 <Text> </Text> 처럼 여는 태그와 닫는 태그로 나누어진 경우가 있다. HTML로 따지면 <link /> 와 <body> </body> 정도가 되겠다. <View> 태그 안에 존재 해야한다는 뜻인거 같다.return에 의해 렌더링 될 땐 항상 소괄호로 감싸져야 한다.return() 소괄호 안에 렌더링 될 태그와 코드가 들어가야 하는 것 아닌가...?return() 안에서는 JSX 문법을 사용하고 이외에는 다른 문법을 사용하기 때문에, 주석 처리 코드도 다르다. return() 안에선ㄴ /* */를 사용하고 이외에선 // 를 쓰면 되겠다.<View>div 쯤 된다.<Text><ScrollView><View> 대신 이 태그를 사용하면 된다.<Button>과 함수return() 밖에서 함수를 정의하여 불러 오면 된다.<TouchableOpacity/><Button>대신 이 친구를 사용한다고한다. 디자인 자유도가 더 높다는 이유인거 같다. 그냥 <View>에 터치 상호작용을 넣는 것과 똑같다고 보면 된다.<Image><Image
source={{uri:'https://images.unsplash.com/photo-1424819827928-55f0c8497861?fit=crop&w=600&h=600%27'}}
// 사용설명서에 나와 있는 resizeMode 속성 값을 그대로 넣어 적용합니다
resizeMode={"cover"}
style={styles.imageStyle}
/>
강의 자료엔 flex에 대한 것도 나와 있는데 아는 내용이라 생략!

위와 같은 화면을 만드는 것이다 아래는 내가 작성한 코드
import React from 'react'
import {
StyleSheet,
Text,
View,
Image,
TouchableOpacity,
ScrollView,
} from 'react-native'
export default function App() {
return (
<View style={styles.container}>
<Text style={styles.appName}>나만의 꿀팁</Text>
<Image
source={{
uri: 'https://storage.googleapis.com/sparta-image.appspot.com/lecture/main.png',
}}
resizeMode={'contain'}
style={styles.mainImage}
/>
<ScrollView horizontal style={styles.btns}>
<TouchableOpacity style={styles.btn1}>
<Text style={styles.btnText}>생활</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.btn2}>
<Text style={styles.btnText}>재테크</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.btn3}>
<Text style={styles.btnText}>반려견</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.btn4}>
<Text style={styles.btnText}>꿀팁 찜</Text>
</TouchableOpacity>
</ScrollView>
<View style={styles.contentContainer}>
<View style={styles.contents}>
<Image
style={styles.thumbnail}
source={{
uri: 'https://storage.googleapis.com/sparta-image.appspot.com/lecture/pizza.png',
}}
/>
<View style={styles.content}>
<Text style={styles.contentTitle}>
먹다 남은 피자를 촉촉하게!
</Text>
<Text style={styles.contentDesc} numberOfLines={3}>
먹다 남은 피자는 수분이 날라가기 때문에 처음처럼
맛있게 먹을 수 없는데요. 이럴 경우 그릇에 물을 받아
전자레인지 안에서 1분 30초에서 2분 정도 함께
돌려주면 촉촉하게 먹을 수 있습니다. 물이 전자레인지
안에서 수증기를 일으키고, 피자에 촉촉함을
더해줍니다.
</Text>
<Text style={styles.contentDate}>2020.09.09</Text>
</View>
</View>
</View>
</View>
)
}
const styles = StyleSheet.create({
container: {
padding: 10,
paddingTop: 40,
},
appName: {
fontSize: 20,
fontWeight: '700',
},
mainImage: {
width: '90%',
height: 200,
borderRadius: 10,
marginTop: 20,
alignSelf: 'center',
},
btns: {
marginTop: 20,
marginLeft: 10,
height: 60,
},
btn1: {
width: 100,
height: 50,
borderRadius: 15,
margin: 7,
padding: 15,
backgroundColor: 'orange',
},
btn2: {
width: 100,
height: 50,
borderRadius: 15,
margin: 7,
padding: 15,
backgroundColor: 'pink',
},
btn3: {
width: 100,
height: 50,
borderRadius: 15,
margin: 7,
padding: 15,
backgroundColor: 'lightblue',
},
btn4: {
width: 100,
height: 50,
borderRadius: 15,
margin: 7,
padding: 15,
backgroundColor: 'violet',
},
btnText: {
textAlign: 'center',
fontWeight: '700',
color: 'white',
},
contentContainer: {
height: 150,
marginTop: 10,
marginLeft: 10,
},
contents: {
flex: 1,
flexDirection: 'row',
margin: 10,
borderBottomWidth: 0.5,
borderBottomColor: '#eee',
paddingBottom: 10,
},
thumbnail: {
flex: 1,
width: 100,
height: 100,
borderRadius: 10,
},
content: {
flexDirection: 'column',
flex: 2,
marginLeft: 10,
},
contentTitle: {
fontSize: 20,
fontWeight: '700',
},
contentDesc: {
fontSize: 15,
color: 'black',
},
contentDate: {
fontSize: 10,
color: '#a6a6a6',
},
})
아래는 완성 화면

강의자료에서 제공하는 답이랑 Style 쪽이 다른게 몇개 있는데,
<ScorllView> 대신 <View><View>로 만들었다. 이게 3번 문제의 발단이다<SafeAreaView>를 쓰면 상태바에 글씨나 이미지가 안 가려지고 출력 된다는데 나는 안되서 임의로 40을 넣어 줬다.<View>의 높이 지정)
사진으로 보다시피 desc에 있는 글이 뜨지 않는다. 알고보니 contentContainer의 높이를 지정해 주지 않았었다... 근데 이상하게 <ScrollView>를 쓰면 딱히 지정해주지 않아도 정상적으로 글이 뜨는 것이었다. 즉문즉답 게시판에 여쭈어보니 <View>나 <SafeAreaView>로 최상위 태그를 감싸면 엘리먼트들의 높이를 지정해 주어야 하는 것 같다. 피자 사진이 뜨는 이유는 피자 사진만 높이를 정해줬었다 ㅋㅋㅋ
근데 웹 구동을 했을 땐 높이를 지정하지 않아도 잘 나온다. 브라우저가 알아서 높이를 정해주기 때문인가...?
위에서 잠깐 언급한 import에 관한 정보이다. 아래 코드를 보자.
//A.js 파일
//times, plusTwo 함수를 외부로 내보낼 준비를 합니다.
export function times(x) {
return x * x;
}
export function plusTwo(number) {
return number + 2;
}
//B.js 파일
//다른 자바스크립트 파일에서 다음과 같이 불러와 사용합니다.
import { times, plusTwo } from './A.js';
console.log(times(2));
console.log(plusTwo(3));
A.js 코드를 보면 times(x)와 pulsTwo(number)라는 함수 두 개를 export한다고 되어 있다. 이를 B.js에서 import로 불러오는데, 사용법은 아래와 같다
import {함수1, 함수2, ...} from '함수를 불러올 파일 주소';
이렇게 외부 데이터나 함수를 가져다가 쓰는 것을 모듈 시스템이라고 한다.
이렇게 보니 메인화면에 해당되는 App.js파일에도 비슷한 함수가 있다.
export default function App() { ... }
이 함수 또한 어디론가 모듈화 되서 나가고 있는 것이다. 화면을 그리는 함수(App())가 내보내져서 어디선가 사용이 되어 화면을 그리게 된다는 뜻이다. 그래서 앞으로도 여러 앱 파일을 만들 때, export default function를 통해서 함수를 내보낼 계획이라고 한다.
위에서 함수뿐만아니라 데이터도 모듈시스템으로 가져올 수 있다고 했는데, 대표적인 예로 JSON파일을 가져다가 쓸 수 있다. 아래는 JSON 구조의 파일이다.
{
"tip":[
{
"idx":0,
"category":"생활",
"title":"먹다 남은 피자를 촉촉하게!",
"image":"https://storage.googleapis.com/sparta-image.appspot.com/lecture/pizza.png",
"desc":"먹다 남은 피자는 수분이 날라가기 때문에 처음처럼 맛있게 먹을 수 없는데요. 이럴 경우 그릇에 물을 받아 전자레인지 안에서 1분 30초에서 2분 정도 함께 돌려주면 촉촉하게 먹을 수 있습니다. 물이 전자레인지 안에서 수증기를 일으키고, 피자에 촉촉함을 더해줍니다.",
"date":"2020.09.09"
},
{
"idx":1,
"category":"생활",
"title":"바나나를 싱싱하게 보관하기",
"image": "https://storage.googleapis.com/sparta-image.appspot.com/lecture/banana.png",
"desc":"바나나에 날파리가 꼬이거나 금방 익어버리는 것을 예방하기 위한 방법인데요. 바나나 양쪽 끝을 자른 후, 보관용 케이스나 비닐봉지에 묶어 밀봉합니다. 그리고 냉장고에 넣어주면 되는데요. 하루에 1~2개씩 꺼내서 싱싱하게 먹을 수 있습니다.",
"date":"2020.09.09"
},
{
"idx":2,
"category":"생활",
"title":"셔츠에 묻은 볼펜 자국 없애기",
"image": "https://storage.googleapis.com/sparta-image.appspot.com/lecture/shirt.png",
"desc":"셔츠를 자주 입는 사람의 경우, 종종 볼펜 자국이 묻기 마련인데요. 이럴 경우에는 집에 있는 물파스로 가볍게 지울 수 있습니다. 옷 뒷부분을 키친타올로 받쳐 번지는 것을 방지한 후, 볼펜 자국 있는 부분을 물파스로 눌러주고, 키친타올로 닦아냅니다.",
"date":"2020.09.09"
},
{
"idx":3,
"category":"재테크",
"title":"잠자는 내 돈을 찾아라",
"image": "https://storage.googleapis.com/sparta-image.appspot.com/lecture/money1.png",
"desc":"‘새는 돈’에는 미처 몰랐던 카드 포인트, 휴면예금이나 환급금도 포함됩니다. 확실히 파악하지 못한 잠자는 돈을 찾아보고 자투리 돈들을 모으는 것도 중요합니다. 케이블방송, 위성방송 서비스를 이용하면서 중복 납부한 요금, 셋톱박스 보증금 등 돌려받지 않은 돈이 있는지 확인 해보세요. 또, 카드 포인트 통합 조회 서비스를 이용해 여러 개의 카드 포인트가 모두 얼마인지 체크해두는 것이 좋습니다. 보험해약 환급금, 휴면 보험금이나 휴면 예금을 찾아보고 돌려받는 일도 요즘에는 어렵지 않습니다.",
"date":"2020.09.09"
},
{
"idx":4,
"category":"재테크",
"title":"할인행사, 한정할인판매 문구의 함정 탈출!",
"image": "https://storage.googleapis.com/sparta-image.appspot.com/lecture/money2.png",
"desc":"‘안 사면 100% 할인’이라는 말 들어보셨나요? 견물생심, 좋은 물건을 보면 사고 싶기 마련입니다. 특히 대대적인 ‘할인 행사’ 중인 대형 마트에 갔을 때는 말할 것도 없겠죠. 따라서 생필품을 살 때, 한꺼번에 사서 사용하는 것보다 필요할 때 조금씩 구매하는 편이 좋습니다. 장을 보면서 대형마트에 자주 가다 보면 지금 필요한 것뿐 아니라 앞으로 필요할 것까지 사게 되어 지출이 커지기 때문입니다. 특히 할인 품목을 보면 뜻하지 않은 소비를 하는 경우도 많아진다. 홈쇼핑, 대형마트 등의 ‘할인행사’, ‘한정할인판매’ 등의 문구를 조심하세요. ",
"date":"2020.09.09"
},
{
"idx":5,
"category":"생활",
"title":"방전된 건전지 살리기",
"image": "https://storage.googleapis.com/sparta-image.appspot.com/lecture/battery.png",
"desc":"건전지를 다 사용하지 않아도 방전되면, 버리는 경우가 종종 있는데요. 건전지의 무게감이 느껴진다면, 드라이기를 활용해 방전된 건전지를 깨울 수 있습니다. 드라이기 열기를 10초~30초 정도 골고루 가해주면 되는데요. 건전지가 불필요하게 낭비되는 것을 막을 수 있습니다.",
"date":"2020.09.09"
},
{
"idx":6,
"category":"반려견",
"title":"반려견에게 배변 교육 시킬 때",
"image": "https://storage.googleapis.com/sparta-image.appspot.com/lecture/puppy.png",
"desc":"우선, 배변패드를 순서대로 돌며 간식을 조금씩 떨어뜨려 놓는다. 2단계는 배변패드 앞에서 기다렸다 반려견이 스스로 올라오면 간식을 주어서 보상하고, 3단계는 “화장실 가자”나 “매트” 같은 명령어를 붙여 말한 뒤 배변패드에 올라오면 간식을 주는 것이다. 마지막 단계는 배변패드에 올라간 반려견이 대소변을 본 다음 간식을 줌으로써 이 장소가 즐거운 곳이라는 인식을 심어주는 것이다. 그리고 무엇보다 1, 2회 사용한 배변패드는 바로 갈아줘야 한다.",
"date":"2020.09.09"
},
{
"idx":7,
"category":"반려견",
"title":"반려견이 주인과 떨어지는 것을 무서워 할 때",
"image": "https://storage.googleapis.com/sparta-image.appspot.com/lecture/puppy2.png",
"desc":"분리불안교육은 반려견에게 혼자 남는 법을 알려주기 위한 것이 아니라, 보호자가 ‘언제나 너에게 돌아올 거야’라고 알려주는 교육이다. 반려견과 5초 동안 떨어져 있다가 다시 문을 열고 들어가 손 냄새를 맡게 해주는 훈련을 하루 10번씩 7일 동안 반복하는 ‘5,10,7 법칙’을 통해 반려견의 마음을 편안하게 해줄 수 있다.",
"date":"2020.09.09"
},
{
"idx":8,
"category":"반려견",
"title":"반려견을 아이와 함께 키울 때",
"image": "https://storage.googleapis.com/sparta-image.appspot.com/lecture/puppy3.png",
"desc":"‘인간의 행복’을 위해 반려동물을 키우는 것에 대해 꾸준히 비판과 우려를 제기해온 그는 특히 ‘아이들의 정서’를 위해 반려견을 키우려 한다는 부모들에게 당부한다. “반려동물을 통해 아이들의 정서가 좋아진다면, 그것은 부모가 나와 생김새와 느낌, 말과 행동이 다른 동물을 아끼는 모습을 보기 때문입니다.” 인간의 뜻에 의해 인간과 함께 살게 된 생명을 좀 더 이해하고 행복하게 살 수 있도록 하는 것은 역시 인간의 노력에 달려 있다.",
"date":"2020.09.09"
},
{
"idx":9,
"category":"재테크",
"title":"렌탈 서비스 금액 비교해보기",
"image": "https://storage.googleapis.com/sparta-image.appspot.com/lecture/money2.png",
"desc":"요즘은 정수기, 공기 청정기, 자동차나 장난감 등 다양한 대여서비스가 활발합니다. 사는 것보다 경제적이라고 생각해 렌탈 서비스를 이용하는 분들이 늘어나고 있는데요. 다만, 이런 렌탈 서비스 이용이 하나둘 늘어나다 보면 그 금액은 겉잡을 수 없이 불어나게 됩니다. 특히, 렌탈 서비스는 빌려주는 물건의 관리비용까지 포함된 것이기에 생각만큼 저렴하지 않습니다. 직접 관리하며 사용할 수 있는 물건이 있는지 살펴보고, 렌탈 서비스 항목에서 제외해보세요. 렌탈 비용과 구매 비용, 관리 비용을 여러모로 비교해보고 고민해보는 것이 좋습니다. ",
"date":"2020.09.09"
}
]
}
이런 JSON 파일을 불러오면 아래와 같이 map() 함수를 이용해 많은 양의 데이터를 간결한 코드로 불러 올 수 있다.
import React from 'react';
import { StyleSheet, Text, View, Image, TouchableOpacity, ScrollView} from 'react-native';
const main = 'https://firebasestorage.googleapis.com/v0/b/sparta-image.appspot.com/o/lecture%2Fmain.png?alt=media&token=8e5eb78d-19ee-4359-9209-347d125b322c'
import data from './data.json'; // data라는 이름으로 data.json을 불러옴
export default function App() {
let tip = data.tip; // 여기서 data.json을 보면 tip이라는 리스트 안에 객체들의 정보가 들어가 있기 때문에 tip이라는 value를 넣어주는 것이다.
let todayWeather = 10 + 17;
let todayCondition = "흐림"
//return 구문 밖에서는 슬래시 두개 방식으로 주석
return (
/*
return 구문 안에서는 {슬래시 + * 방식으로 주석
*/
<ScrollView style={styles.container}>
/* 위에 파트 생략 */
<View style={styles.cardContainer}>
{/* 하나의 카드 영역을 나타내는 View */}
{
tip.map((content,i)=>{ /* map() 함수를 이용해 JSON 데이터 안에 있는 정보를 기반으로 카드들을 그려준다.*/
return (<View style={styles.card} key={i}> /* 이때 카드마다 고유의 key를 붙여주어 다른 카드의 정보가 바뀌어도 같이 바뀌지 않도록 해주어야 한다. */
<Image style={styles.cardImage} source={{uri:content.image}}/> /* content는 각 객체이다 */
<View style={styles.cardText}>
<Text style={styles.cardTitle} numberOfLines={1}>{content.title}</Text>
<Text style={styles.cardDesc} numberOfLines={3}>{content.desc}</Text>
<Text style={styles.cardDate}>{content.date}</Text>
</View>
</View>)
})
}
</View>
</ScrollView>
);
}
// styels 생략
삼항 연산자를 알고 있지만 이것을 {} 표현식 안에서도 간단히 조건문을 구성할 수 있다.
JavaScript에서 삼항 연산자의 기본 사용법은 이와 같다
let 변수명 = 조건문 ? 참 : 거짓
위와 코드가 동일하지만 키값의 짝홀 여부에 따라 카드 배경색이 달라지는 코드이다 그 부분만 퍼왔다.
/* ~~ 생략 */
<View style={styles.cardContainer}>
{/* 하나의 카드 영역을 나타내는 View */}
{
tip.map((content,i)=>{
/* 여기서는 JSX문법으로 let을 사용하지 않고 return 문으로 조건에 따라 결정되는 엘리먼트를 바로 화면에 반환 하는 방식을 사용했다.*/
return i % 2 == 0 ? (<View style={styles.cardEven} key={i}>
<Image style={styles.cardImage} source={{uri:content.image}}/>
<View style={styles.cardText}>
<Text style={styles.cardTitle} numberOfLines={1}>{content.title}</Text>
<Text style={styles.cardDesc} numberOfLines={3}>{content.desc}</Text>
<Text style={styles.cardDate}>{content.date}</Text>
</View>
</View>) : (<View style={styles.cardOdd} key={i}>
<Image style={styles.cardImage} source={{uri:content.image}}/>
<View style={styles.cardText}>
<Text style={styles.cardTitle} numberOfLines={1}>{content.title}</Text>
<Text style={styles.cardDesc} numberOfLines={3}>{content.desc}</Text>
<Text style={styles.cardDate}>{content.date}</Text>
</View>
</View>)
})
}
</View>
/* 생략 */

위와 같은 화면을 만드는게 숙제이다. 내가 만든 코드를 보기 전에 새롭게 공부한 것!
프로젝트 하위 폴더로 'pages'라는 폴더를 생성하고 안에 js파일을 만들면 새로운 앱 화면을 구성할 수 있다. 이를 App.js
return()문 안에서 불러오면 앱 실행시 바로 그 화면이 나온다. 아래 코드를 참고!

이렇게 page 폴더를 만들어서 js 파일을 새로 담으면 된다. 그리고 아래와 같이 불러온다.
// App.js
import React from 'react'
import MainPage from './pages/MainPage'
import AboutPage from './pages/AboutPage'
export default function App() {
/* return <MainPage />*/ /* 기존 숙제에 있던 코드는 여기에 옮겼다. (나만의 꿀팁)*/
return <AboutPage />
}
그리고 아래는 내가 제출한 숙제 코드! (AboutPage 코드)
import React from 'react'
import { View, Text } from 'react-native'
import { StyleSheet, TouchableOpacity, Image } from 'react-native-web'
const main =
'https://firebasestorage.googleapis.com/v0/b/sparta-image.appspot.com/o/lecture%2FaboutImage.png?alt=media&token=13e1c4f6-b802-4975-9773-e305fc7475c4'
export default function AboutPage() {
return (
<View style={styles.container}>
<Text style={styles.title}>
HI! 스파르타코딩 앱개발 반에 오신 것을 환영합니다!
</Text>
<View style={styles.card}>
<Image
style={styles.cardImg}
source={{ uri: main }}
resizeMode={'cover'}
/>
<Text style={styles.desc1}>
많은 내용을 간결하게 담아내려 노력했습니다!
</Text>
<Text style={styles.desc2}>
꼭 완주 하셔서 곡 여러분 것으로 만들어 가시길 바랍니다
</Text>
<TouchableOpacity style={styles.btn}>
<Text style={styles.btnTxt}>@chosen.1_errSum</Text>
</TouchableOpacity>
</View>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#1F266A',
alignItems: 'center',
},
title: {
// 폰트 크기
fontSize: 30,
// 폰트 굴기
fontWeight: '700',
paddingLeft: 30,
paddingTop: 100,
paddingRight: 30,
// 텍스트 색깔
color: 'white',
},
card: {
backgroundColor: 'white',
justifyContent: 'center',
alignItems: 'center',
width: 300,
height: 500,
borderRadius: 30,
marginTop: 50,
marginBottom: 50,
},
cardImg: {
width: 150,
height: 150,
borderRadius: 30,
},
desc1: {
textAlign: 'center',
fontSize: 20,
fontWeight: '700',
paddingLeft: 22,
paddingRight: 22,
},
desc2: {
textAlign: 'center',
fontSize: 15,
fontWeight: '700',
padding: 22,
},
btn: {
padding: 20,
backgroundColor: 'orange',
borderRadius: 15,
},
btnTxt: {
fontSize: 15,
fontWeight: '700',
color: 'white',
},
})
개발엔 딱히 어려움은 없었다. 다만 margin, padding 수치와 색 코드는 답안을 보고 좀 참고 했다. 이런 감각이 없어서 디자인을 못하겠다. ㅠㅠ
끝!