직딩 개발기-CollapsibleView
직딩의 홈 화면에는 여러 항목이 나타나는 데요.
각 항목을 접었다 폈다 할 수 있어야 했어요.
그러려면 당연히 Tap을 할 수 있어야 하겠죠.
먼저 View를 TouchableOpacity로 대체합니다.
export const CalculationView: ICalculationView = ({style}) => {
...
return (
<TouchableOpacity style={[styles.container, style]}>
그리고 지금 접힌 상태인지 펴진 상태인지 기억하기 위해 state를 선언해야해요.
const [isCollapsed, setIsCollapsed] = useState(false)
그리고 Tap할 때 마다 그 상태를 반전시켜주면 되죠.
const onToggle: GestureEventHandler = () => {
setIsCollapsed(!isCollapsed)
}
return (
<TouchableOpacity style={[styles.container, style]} onPress={onToggle}>
그런데 Component를 숨기려면 어떻게 해야 할까요?
아주 간단하게는 그냥 rendering이 되지 않게 하는거죠.
return (
<View>
{isVisible && <CalculationView ... />}
</View>
)
하지만 이렇게 하면 안보였다 다시 보일때마다 CalculationView가 다시 Mount 될거에요.
두번째 방법은 opacity를 정해서 투명하게 보이게 하는 것이죠.
opacity: 0
그러나 이 방법도 역시 문제가 있습니다. 눈에는 안보이지만 공간은 차지하고 있기 때문이죠.
그럼 방법이 없는 걸까요?
Style 속성 중에는 display 속성이 있는데 이것을 none으로 설정하면 원하는대로 됩니다.
펴져야 할 때는 flex로 접어야할 때는 none으로 바뀌주는 것이죠.
<View style={[styles.contentList, {display: isCollapsed ? 'none' : 'flex'}]}>
<View style={[styles.separator, {display: isCollapsed ? 'none' : 'flex'}]} />
<View style={[styles.descriptionContainer, {display: isCollapsed ? 'none' : 'flex'}]}>
그런데 저는 {display: isCollapsed ? ‘none’ : ‘flex’} 가 반복되는게 싫었어요. flex라는게 가독성도 떨어진다고 생각해서 헬퍼를 만들었죠.
helpers/react.ts
export const displayStyle = (visible: boolean): FlexStyle => {
return {
display: visible ? 'flex' : 'none',
}
}
그리고 그걸로 대체했어요.
<View style={[styles.contentList, displayStyle(!isCollapsed)]}>
그리고 실행해서 Tap으로 접어지는 것을 확인할 수 있었어요.
그런데 이대로는 접고 펼칠 수 있다는 걸 인지하기 어렵죠.
그래서 현재 펼친 상태인지 접은 상태인지 나타내는 아이콘을 추가했어요.
styles.ts
collapseIconContainer: {
width: 24,
height: 24,
},
collapseIcon: {
fontSize: 20,
color: Colors.white,
},
index.tsx
<View style={styles.collapseIconContainer}>
<Text style={styles.collapseIcon}>{isCollapsed ? '▸' : '▼'}</Text>
</View>
인지는 할 수 있지만 완전히 다른 문자라 크기가 달라서 보기가 좋지 않았어요. 나중에 아이콘 이미지 적용할 때를 생각해서라도 다른 방법을 사용해야 했죠.
Style 속성 중에는 transform 라는 것이 있는데 이것으로 View를 회전시킬 수가 있어요.
이걸 이용해서 같은 아이콘을 90도 회전 시켰더니
<View style={styles.collapseIconContainer}>
<Text style={[styles.collapseIcon, !isCollapsed && {transform: [{rotate: '90deg'}]}]}>{'▸'}</Text>
</View>
이제 좀 괜찮아졌네요.
보기에는 문제 없어보이지만 사실 회전된 위치에 문제가 있었는데,
lineHeight를 주고 가운데 정렬해서 해결할 수 있었죠.
collapseIcon: {
fontSize: 20,
color: Colors.white,
borderWidth: 1,
borderColor: Colors.white,
textAlign: 'center',
lineHeight: 24,
},
사실 이문제는 이미지 아이콘을 사용하면 발생하지 않을 문제에요.
최종 완성된 화면입니다!