1. 코드 리뷰
(1) App.js
export default function App() {
const [isOpened, setIsOpened]=useState(true);
const [selectedTabIdx, setSelectedTabIdx] = useState(0);
const onPressArrow = () => {
console.log("clicked arrow")
setIsOpened(!isOpened)
}
return (
<View style={styles.container}>
<View style={{
flex: 1,
paddingHorizontal: 15,
}}>
<Header />
<Margin height = {10}/>
<Profile
uri={myProfile.uri}
name={myProfile.name}
introduction={myProfile.introduction}
/>
<Margin height={15}/>
<Division/>
<Margin height={12}/>
<FriendSection
friendProfileLen = {friendProfiles.length}
onPressArrow={onPressArrow}
isOpened = {isOpened}
/>
<FriendList
data = {friendProfiles}
isOpened = {isOpened}
/>
</View>
<TabBar
selectedTabIdx = {selectedTabIdx}
setSelectedTabIdx = {setSelectedTabIdx}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
paddingTop: statusBarHeight,
},
});
a. tabBar 제외한 모든 컴포넌트들은 view로 한번 더 묶었다. 그리고 해당 View의 flex를 1로 지정해주었다.
flex: 1은 flex-basis:0, flex-grow: 1, flex-shrink: 1 로써 고정너비 없이 화면 크기에 따라 늘어나고 줄어들겠다는 뜻이다.
만약에 형제 요소도 flex가 지정되어 있다면 그들 사이의 flex 값의 비율에 따라 서로 차지할 너비가 정해진다.
A 요소의 flex가 3이고, B 요소의 flex가 7이면 해당 형제 요소들은 3: 7의 비율로 너비를 차지 한다.
여기서는 tabbar는 따로 flex를 정해주지 않았기 때문에 자신의 고정 너비 만큼만 화면을 차지 한다.
따라서 다른 영역들의 view의 flex:1이므로 나머지 영역을 다 차지할 수 있게 되는 것이다.
b. FriendList의 ScrollView에 있던 paddingBottom을 지운다.
why? 리스트에 패딩 바텀이 있었던 이유는 스크롤 되는 내용과 폰 내장 버튼들이 서로 겹치지 않게 하기 위해서 였다.
하지만 TabBar를 생성하면서 부터, List는 직접적으로 폰 내장 버튼들과 접촉이 없어졌다.
이제 paddingBottom이 있으면 TabBar와 List 사이에 여백이 생겨버리기 때문에 지웠다.
c. selectedTabIdx UseState
0,1,2,3의 상태를 둬서 각각 맨 왼쪽부터 버튼을 눌렀을 시 바뀌는 값 들이다.
selectedTabIdx와 함수 setSelectedTabIdx 를 인자로 TabBar에 넣는다.
(2) TabBar 컴포넌트 내부
export default ({selectedTabIdx, setSelectedTabIdx}) => {
return(
<View style={{
flexDirection: "row",
width: "100%",
padding: bottomSpace,
borderTopWidth: 0.5,
borderTopColor: "grey"
}}>
<TabButton
isSelected={selectedTabIdx === 0}
onPress = {() => setSelectedTabIdx(0)}
activeIconName={"person"}
inactiveIconName= {"persons"}
isIconFontisto
/>
<TabButton
isSelected={selectedTabIdx === 1}
onPress = {() => setSelectedTabIdx(1)}
activeIconName={"chatbubble"}
inactiveIconName= {"chatbubble-outline"}
isIconIonicons
/>
<TabButton
isSelected={selectedTabIdx === 2}
onPress = {() => setSelectedTabIdx(2)}
activeIconName={"pricetag"}
inactiveIconName= {"pricetag-outline"}
isIconIonicons
/>
<TabButton
isSelected={selectedTabIdx === 3}
onPress = {() => setSelectedTabIdx(3)}
activeIconName={"add-circle"}
inactiveIconName= {"add-circle-outline"}
isIconIonicons
/>
</View>
)
}
props로 안 받고, 속성 자체를 직접 받아도 된다.
이때 인수를 여러 개 받을 경우 { }으로 한 번 감싸줘야 한다.
TabBar 내에 flexDirection: "row"로 해서 버튼을 4개 만든다.
버튼은 중복되므로 따로 함수로 뺀다.
const TabButton= ({
isSelected,
onPress,
activeIconName,
inactiveIconName,
isIconFontisto,
isIconIonicons,
}) => {
return(
<TouchableOpacity
activeOpacity={1}
onPress={onPress}
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
paddingVertical: 10,
}}>
{isIconFontisto && <Fontisto name={isSelected? activeIconName : inactiveIconName} size={24} color="black" />}
{isIconIonicons && <Ionicons name={isSelected? activeIconName : inactiveIconName} size={24} color="black" />}
</TouchableOpacity>
)
}
TabButton의 인수 설명
isSelected는 해당 버튼이 선택되었는가? 이다.
동등 연산자 (===)을 통해 해당 버튼이 대표하는 넘버를 useState 변수가 가지고 있는지 확인한다.
isSelected={selectedTabIdx === 1}
상태 변수가 1이면 지금 맨 왼쪽 버튼이 눌러져있는 상태 라고 볼 수 있다.
onPress 함수
해당 버튼을 눌렀을 때 동작하는 속성이다.
함수가 눌러졌다면 selectedTabIdx가 해당 버튼의 대표 번호로 바뀌어야 한다.
onPress = {() => setSelectedTabIdx(1)}
activeIcon, inActiveIcon
선택 되었을 때랑 안 되었을 때랑 아이콘이 달라야 한다.
이를 삼항 연산자로 구현했다.
name={isSelected? activeIconName : inactiveIconName}
isIconFontisto, isIconIonicons
아이콘을 수입해온 번지 수가 서로 틀리다. 따라서
상위 컴포넌트에서 무슨 아이콘 사용하는지 받고 그 아이콘을 사용하면 하위 컴포넌트에서 해당 아이콘으로 작업하도록 해야한다.
먼저 상위 컴포넌트에서 어떤 종류의 아이콘 사용하는지는 다음과 같이 나타낸다.
<TabButton
isSelected={selectedTabIdx === 1}
onPress = {() => setSelectedTabIdx(1)}
activeIconName={"chatbubble"}
inactiveIconName= {"chatbubble-outline"}
isIconIonicons
/>
해당 button은 Ionicons를 쓰는 것을 알 수 있다.
위와 같이 그냥 속성 자체를 적어놓는 것만으로도 true 이다.
속성이 안 적혀 있으면 false 이다.
위 내용은 TabButton 내부 로직이고, 만약 Fontisoicon 쓰면 위에꺼 발동, Ionicon 쓰면 밑에 거 발동이다.
** 참고 **
이렇게 적으면, TouchOpacity 태그 눌렀을 때도 안 흐려진다. 불투명도를 100%로 한 것
2. 직접 해보기
1. main 매소드에서 tabBar와 다른 컴포넌트들 간의 크기 조정 (탭바- 고정불변, 다른 메소드들 화면 크기에 따라서 가변적)
2. List의 paddingBottom 지우기. (tabBar와의 공백 없애기)
3. 상태함수 만들어서 TabBar에 대입
4. TabBar에서 홈버튼 만들기. (눌려졌을 때 아닐 때 다른 아이콘 / 눌렀을 떄 흐려지는 것 없애기)
완성 제대로 돌아감!
주의할 점
컴포넌트의 인수로 값이 복수로 들어올 경우
{}로 감쌀 것
'모바일 개발 > React Native-이론' 카테고리의 다른 글
컴포넌트 스타일링 (0) | 2023.04.04 |
---|---|
Scroll View 대신 FlatList 사용해보기 (0) | 2023.04.03 |
친구리스트 토글 버튼 만들기 (0) | 2023.03.27 |
카카오톡 클론코딩 친구리스트 만들기 (0) | 2023.03.27 |
카카오톡 클론코딩 My Profile 만들기 (0) | 2023.03.26 |