내일배움단 App3.1
[앱개발 종합반] 3주 1일차 개발일지(3주 1강)
📱TIL App.301
복습: 나만의 꿀팁 앱 상세화면 만들기
1. 예시 이미지 / 나의 결과 이미지


2. 예시 이미지 보고 스스로 해보기
1) 사전 준비
// DetailPage.js
import React from 'react';
import { StyleSheet, Text, View, Image, TouchableOpacity, ScrollView } from 'react-native';
export default function () {
console.disableYellowBox = true;
return ()
}
const styles = StyleSheet.create({
})
// App.js
import React from 'react'
import MainPage from './pages/MainPage'
import AboutPage from './pages/AboutPage'
import DetailPage from './pages/DetailPage'
export default function App() {
// return (<MainPage/>)
// return (<AboutPage/>)
return (<DetailPage/>)
}
새로운 페이지를 만들기 위해서, 가장 먼저 pages
폴더에 DetailPage.js
파일을 만들고, 위와 같은 기본 구조를 세팅한다. 파일 이름과 함수 이름이 같아야 하므로 함수 이름을 DetailPage
로 설정한 후, 기기 화면에서 노란색 권고사항 창을 숨기기 위해 console.disableYellowBox = true;
코드를 추가한다. 이 코드는 각 페이지 파일마다 추가해도 되고, App.js
파일에만 추가해도 된다. App.js
파일에서는, 이전에 불러온 <Mainpage/>
와 <AboutPage.js/>
태그를 주석 처리하고, <DetailPage/>
태그를 추가한다.
⚠️ console.disableYellowBox = true
는 deprecated라는 메세지가 떴다. 공식 문서에 따르면 LogBox.ignoreAllLogs(value)
로 대체될 예정이라고 한다. console.disableYellowBox = true;
대신 LogBox.ignoreAllLogs(true)
를 사용하라는 경고 메세지이지만, 해당 코드를 제거해도 동작에는 문제가 없다.
import React from 'react';
import { StyleSheet, Text, View, Image, TouchableOpacity, ScrollView} from 'react-native';
export default function DetailPage() {
console.disableYellowBox = true;
const tip = {
"idx":9,
"category":"재테크",
"title":"렌탈 서비스 금액 비교해보기",
"image": "https://firebasestorage.googleapis.com/v0/b/sparta-image.appspot.com/o/lecture%2Frental.png?alt=media&token=97a55844-f077-4aeb-8402-e0a27221570b",
"desc":"요즘은 정수기, 공기 청정기, 자동차나 장난감 등 다양한 대여서비스가 활발합니다. 사는 것보다 경제적이라고 생각해 렌탈 서비스를 이용하는 분들이 늘어나고 있는데요. 다만, 이런 렌탈 서비스 이용이 하나둘 늘어나다 보면 그 금액은 겉잡을 수 없이 불어나게 됩니다. 특히, 렌탈 서비스는 빌려주는 물건의 관리비용까지 포함된 것이기에 생각만큼 저렴하지 않습니다. 직접 관리하며 사용할 수 있는 물건이 있는지 살펴보고, 렌탈 서비스 항목에서 제외해보세요. 렌탈 비용과 구매 비용, 관리 비용을 여러모로 비교해보고 고민해보는 것이 좋습니다. ",
"date":"2020.09.09"
}
return ()
}
const styles = StyleSheet.create({
})
다음으로, 사용할 JSON 데이터를 DetailPage()
함수 안에 입력한다. 입력한 데이터는 하단의 JSX 문법에서 딕셔너리(Object) 형태로 key값에 접근한 후 값을 꺼내 사용할 수 있다.
2) 나의 코드
import React from 'react';
import { StyleSheet, Text, View, Image, TouchableOpacity, ScrollView } from 'react-native';
export default function DetailPage() {
console.disableYellowBox = true;
const tip = {
"idx":9,
"category":"재테크",
"title":"렌탈 서비스 금액 비교해보기",
"image": "https://firebasestorage.googleapis.com/v0/b/sparta-image.appspot.com/o/lecture%2Frental.png?alt=media&token=97a55844-f077-4aeb-8402-e0a27221570b",
"desc":"요즘은 정수기, 공기 청정기, 자동차나 장난감 등 다양한 대여서비스가 활발합니다. 사는 것보다 경제적이라고 생각해 렌탈 서비스를 이용하는 분들이 늘어나고 있는데요. 다만, 이런 렌탈 서비스 이용이 하나둘 늘어나다 보면 그 금액은 겉잡을 수 없이 불어나게 됩니다. 특히, 렌탈 서비스는 빌려주는 물건의 관리비용까지 포함된 것이기에 생각만큼 저렴하지 않습니다. 직접 관리하며 사용할 수 있는 물건이 있는지 살펴보고, 렌탈 서비스 항목에서 제외해보세요. 렌탈 비용과 구매 비용, 관리 비용을 여러모로 비교해보고 고민해보는 것이 좋습니다. ",
"date":"2020.09.09"
}
return (
<ScrollView style={styles.container}>
<View style={styles.imageContainer}>
<Image
source={{uri:tip.image}}
style={styles.detailImage}
/>
</View>
<View style={styles.textContainer}>
<Text style={styles.titleText}>{tip.title}</Text>
<Text style={styles.descText}>{tip.desc}</Text>
<TouchableOpacity style={styles.button}><Text style={styles.buttonText}>팁 찜하기</Text></TouchableOpacity>
</View>
</ScrollView>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "black"
},
imageContainer: {
alignItems: "center"
},
detailImage: {
width: "92%",
height: 415,
marginTop: 50,
borderRadius: 20
},
textContainer: {
alignItems: "center",
marginHorizontal: 20
},
titleText: {
color: "white",
fontSize: 22,
fontWeight: "bold",
marginTop: 30,
marginBottom: 15
},
descText: {
color: "white"
},
button: {
width: 100,
height: 45,
marginTop: 25,
justifyContent: "center",
alignItems: "center",
borderWidth: 2,
borderRadius: 5,
borderColor: "orange"
},
buttonText: {
color: "white"
}
})
3) 🤔 QnA
✅ 이미지를 assets
폴더에서 가져올 때는 코드 최상단에 import
키워드를 사용해서 이미지를 가져온다. 외부 이미지 주소를 사용할 때에는 <Image>
태그의 source
속성의 uri
키 값에 주소를 그대로 입력하거나, 주소를 담은 변수명을 입력한다. 이미지는 영역이 설정되어야 화면에 나온다는 점 잊지 말기!
☑️ 이미지의 width
를 설정한 후 가운데 정렬을 하기 위해서, 웹 개발반에서 HTML을 다룰 때처럼 이미지 태그 스타일의 marginHorizontal
속성에 auto
값을 주었는데 아무런 변화가 없다.
✅ CSS에서 margin
이나 padding
속성은 숫자 외에도 문자열 값을 가질 수 있다. 문자열 값으로는 퍼센트 또는 "auto"
가 올 수 있다. "auto"
는 브라우저가 자동으로 계산하는 값으로, 컨텐츠를 자동으로 가운데 정렬하는 데 사용된다. 다만 React Native에서는 margin
이나 padding
속성값으로 auto
를 지원하지 않는다. 2주차 실습 QnA에서도 언급했지만, React Native는 margin
이라는 하나의 속성에 시계 방향으로 모든 값을 줄 수 있는 축약형 형태도 지원하지 않는다. CSS와 React Native가 헷갈린다면, React Native와 CSS를 비교한 글을 읽어보자.
✅ 앞으로 전체를 감싸는 최상위 태그로 <ScrollView>
를 자주 사용하게 될 것이다. 이때 전체 화면을 가운데 정렬하기 위해 태그에 alignItems
속성을 주게 되면 ‘ScrollView child layout([“alignItems”])must be applied through the contentContainerStyle prop.’이라는 에러 메세지가 뜬다. 전체를 <ScrollView>
로 감쌌다면, 자식 태그로 <View>
태그를 새로 설정해 그 태그에 정렬 속성을 주자.
☑️ 최상위 태그인 <View>
를 <ScrollView>
태그로 바꾸면, 퍼센트 값으로 지정한 이미지의 height
값이 무효 처리된다.
✅ <ScrollView>
태그 자체가 상하 길이에 제한을 두지 않는다는 뜻이기 때문에, 이미지의 높이를 퍼센트로 설정하는 것은 의미가 없다. height
값을 숫자 값으로 주어야 한다.
3. 해설 코드와 배울 점
1) 기본 구조부터!
return (
<ScrollView>
<Image source={}/>
<View>
<Text></Text>
<Text></Text>
<TouchableOpacity><Text></Text></TouchableOpacity>
</View>
</ScrollView>
)
튜터분께선 기본적인 구조를 작성하고, 각 태그의 style
key 이름을 먼저 설정하신 뒤 코드를 짜셨다. 처음부터 너무 복잡하게 생각할 필요 없이, 태그만이라도 기본적인 구조를 잡고 들어가는 게 효율적일 것 같다.
import React from 'react';
import { StyleSheet, Text, View, Image, ScrollView, TouchableOpacity, Alert } from 'react-native';
export default function DetailPage() {
const tip = {
"idx":9,
"category":"재테크",
"title":"렌탈 서비스 금액 비교해보기",
"image": "https://storage.googleapis.com/sparta-image.appspot.com/lecture/money1.png",
"desc":"요즘은 정수기, 공기 청정기, 자동차나 장난감 등 다양한 대여서비스가 활발합니다. 사는 것보다 경제적이라고 생각해 렌탈 서비스를 이용하는 분들이 늘어나고 있는데요. 다만, 이런 렌탈 서비스 이용이 하나둘 늘어나다 보면 그 금액은 겉잡을 수 없이 불어나게 됩니다. 특히, 렌탈 서비스는 빌려주는 물건의 관리비용까지 포함된 것이기에 생각만큼 저렴하지 않습니다. 직접 관리하며 사용할 수 있는 물건이 있는지 살펴보고, 렌탈 서비스 항목에서 제외해보세요. 렌탈 비용과 구매 비용, 관리 비용을 여러모로 비교해보고 고민해보는 것이 좋습니다. ",
"date":"2020.09.09"
}
const popup = () => {
Alert.alert("팝업!!")
}
return (
<ScrollView style={styles.container}>
<Image style={styles.image} source={{uri:tip.image}} />
<View style={styles.textContainer}>
<Text style={styles.title}>{tip.title}</Text>
<Text style={styles.desc}>{tip.desc}</Text>
<TouchableOpacity style={styles.button} onPress={()=>popup()}><Text style={styles.buttonText}>팁 찜하기</Text></TouchableOpacity>
</View>
</ScrollView>
)
}
const styles = StyleSheet.create({
container:{
backgroundColor:"#000"
},
image:{
height:400,
margin:10,
marginTop:40,
borderRadius:20
},
textContainer:{
padding:20,
justifyContent:'center',
alignItems:'center'
},
title: {
fontSize:20,
fontWeight:'700',
color:"#eee"
},
desc:{
marginTop:10,
color:"#eee"
},
button:{
width:100,
marginTop:20,
padding:10,
borderWidth:1,
borderColor:'deeppink',
borderRadius:7
},
buttonText:{
color:'#fff',
textAlign:'center'
}
})
2) ScrollView에서 flex?
튜터분의 설명에 따르면, <ScrollView>
에서의 flex
값은 의미가 없다. 이는 스크롤 기능이 정확히 보여지는 화면을 몇 등분하는 것이 아니라, 화면에 넣은 컨텐츠를 모두 보여주기 위해 존재하기 때문이다. DetailPage 화면에서는 내부 컨텐츠들의 영역을 결정짓기 위해 height
값과 margin
, padding
값을 적절히 잘 이용해야 한다. 코드를 짤 때 습관적으로 flex:1
을 줬는데, <ScrollView>
태그에는 필요 없다!
3) flex
없이 justifyContent
와 alignItems
를?
textContainer:{
padding:20,
justifyContent:'center',
alignItems:'center'
}
예전에 justifyContent
와 alignItems
에 대해 언급하면서, 이 두 속성은 flex
로 지정한 영역 내에서만 이용이 가능하다고 했었다. 그런데 해설 코드 중 일부를 보면, flex
를 사용하지 않고도 내부 컨텐츠가 중앙 정렬되는 모습을 볼 수 있다.
이는 두 속성이 적용되는 textContainer
태그가 하나의 자체 영역을 차지하고 있기 때문에, 즉 해당 태그가 텍스트 태그들의 부모 태그 역할을 하고 있기 때문이다. 따라서 이 태그에느 flex
가 적용되고 있다고 해도 무방하다. 실제로 위 코드에 flex: 1
을 입력해도 보이는 결과값은 같다. 내부 컨텐츠들을 포함한, 영역을 가진 태그이기 때문에 영역 안의 컨텐츠들의 위치를 정렬시킬 수 있는 것이다.
자체적인 영역을 갖고 있는 태그에서는
flex
속성이 적용되고 있다!
위의 코드에 굳이 flex: 1
을 명시적으로 적는다면, 그것은 내부 컨텐츠들의 고유 영역을 비율로 지정하고 싶은 경우다. 이러한 경우가 아니라면, <View>
태그나 <Text>
태그들은 각자 고유한 영역을 갖고 있으므로, 내부 컨텐츠들의 영역 구분을 위해서가 아니라면 flex
를 반드시 쓸 필요는 없다.
4) padding
으로 버튼 크기 조절하기
나는 width
와 height
속성을 사용해서 버튼의 크기를 지정했지만, 버튼 안에 텍스트 컨텐츠가 있으므로 padding
을 주면 버튼의 내부 크기를 키울 수 있다. padding
속성을 사용해 상하좌우 간격을 모두 같은 정도로 띄웠기 때문에, 텍스트는 자동으로 버튼의 가운데에 위치한다. width
값을 더 길게 지정한 경우는 <Text>
태그에 textAlign
속성을 center
로 주면 텍스트가 중앙 정렬된다.
Leave a comment