'React Native 입문기' 시리즈React Native Flexbox와 친해지기

배진오

@baealex

소비적인 일보단 생산적인 일을 좋아합니다.

React Native에선 Flexbox라는 형식으로 레이아웃 개발을 진행한다. 최신 웹 브라우저에서도 이 레이아웃이 작동하여 CSS 최신 방법론으로 알려져 있다. Flexbox는 다양한 화면 크기에서 일관된 레이아웃을 적용할 수 있다. 아래 내용은 대부분 공식문서인 "Layout with Flexbox #"을 인용하였다.


Flex

flex will define how your items are going to “fill” over the available space along your main axis. Space will be divided according to each element's flex property.

플렉스는 축을 기준으로 "채우기"를 정의하며 각 속성의 유연한 속성으로 공간이 나눠진다.



위 레이아웃의 Red는 flex: 1, Orange에는 flex: 2, Green에는 flex: 3이 적용되어있다. 모든 플렉스 값을 더하면 6인데 각 플렉스는 총 플렉스에서 나눠진 값을 크기로 가진다. 즉 Red는 1/6, Green은 3/6의 공간을 가지게 된다. 이 사이즈는 모든 기기에서 반응형으로 동작한다.

전통적인 디자인 방법으로는 vh, calc로 적용할 수 있겠다. 필자의 경우에도 그러는 편이 더 간단하다고 생각되었다. 하지만 플렉스의 장점은 아래와 같은 속성과의 결합으로 도드라진다.


Flex Direction

Flex Direction의 속성으로는 row, column, row-reverse, column-reverse가 존재한다. 기본적으로 Flex Direction은 column으로 설정되어 있는데, 위에서 본 레이아웃도 별도의 Flex Direction을 지정하지 않았기에 세로로 정렬된 것이다.


row
[ 1 ] [ 2 ] [ 3 ]


column
[ 1 ]
[ 2 ]
[ 3 ]

여기까진 충분히 예측할 수 있는 속성이지만


row-reverse
[ 3 ] [ 2 ] [ 1 ]


column-reverse
[ 3 ]
[ 2 ]
[ 1 ]

기존 방법론으로 위와같이 항목을 뒤집으려면 스크립트를 적용해야 할 기능들이 Flex에선 옵션만 하나 바꿔주는 것으로 가능해진다.


Layout Direction

LTR (default value) Text and children are laid out from left to right. Margin and padding applied to the start of an element are applied on the left side.

RTL Text and children are laid out from right to left. Margin and padding applied to the start of an element are applied on the right side.


Justify Content

Justify Content는 flex-start, flex-end, center, space-between, space-around, space-evenly의 속성이 존재하며 기본적으로는 flex-start가 적용되어 있다. 보면 '아... 이거!'인데 막상 텍스트로 표현하긴 어려워서 각각의 이미지로 대체할 예정이다.


flex-start

말 그대로 Flex의 시작 지점에서 컨텐츠가 정렬된다.


flex-end

Flex의 끝 지점에서 컨텐츠가 정렬된다.


center

Flex의 가운데 지점에서 컨텐츠가 정렬된다.


space-between

'아... 이거!'


space-around

'아... 이거?'


space-evenly

이게 around랑 뭐가 다른데?

[ A ][ 1 ][ B ][ 2 ][ C ][ 3 ][ D ]

A, B, C, D가 여백이고 1, 2, 3을 각각의 요소라고 가정한다. around의 경우는

A = D
B = C
B = A * 2

위와같은 특징을 가진다. 한마디로 A와 D가 B의 반정도의 크기이다. 각각의 항목이 앞뒤로 똑같은 여백을 지니는 셈이다. 반면에 evenly는

A = B = C = D

위와같은 특징을 지닌다. 모든 여백이 같은 크기를 가진다.


Align Items

이 속성은 가로축에서 자식을 정렬하는 방법을 지정하는 속성이다. stretch, flex-start, flex-end, center, baseline이 존재하며 stretch가 기본으로 적용되어 있다.


Align Self

이 속성은 자식에게 할당하는 속성으로 자식이 어떻게 정렬될 것인지 스스로 지정한다. Align Self가 적용되면 Align Items를 무시한다. stretch, flex-start, flex-end, center, baseline이 존재하며 stretch가 기본으로 적용되어 있다.


실전 디자인

튜토리얼 문서인 "RN JS 연습 - 투두리스트 만들기 #"를 바탕으로 학습하는 도중에 FLEX와 친해지기 위해서 아래와 같은 레이아웃을 만들어 보고자 하였다.



색상은 필자가 주로 사용하는 색상들#이며 항목을 작성하면 작성한 내용 아래에 생성된 날짜와 날짜와 같은 라인의 끝에는 Done 버튼과 Delete 버튼이 있어야 하는 레이아웃이다. 아래 코드가 나오는데 그냥 맛보기 코드임을 참고하시길 바란다.



우선 입력창을 만들어보자. 입력창의 특징은 인풋 필드가 길게 나열되고 뒤쪽에 추가 버튼만 달아주면 된다. 즉 상위 View에는 flexDirection: 'row'를 적용해주고 첫번째 요소인 TextInput에는 flex: 1을 주고 뒤쪽 버튼에는 원하는 크기 만큼의 너비를 주었다.

<View style={{height: 40, flexDirection: 'row', alignItems: 'center', justifyContent: 'center'}}>
    <TextInput style={{flex: 1, height: 40, borderColor: 'gray', borderWidth: 1}}/>
    <TouchableOpacity style={{width: 80, height: 40, backgroundColor: '#706fd3', borderWidth: 1, borderColor: '#000', alignItems: 'center', justifyContent: 'center'}}
        <Text style={{color: '#fff'}}>
            add Todo
        </Text>
    </TouchableOpacity>
</View>


각각의 항목은 내용 View가 나오고 밑에 하단 View가 나오는데 하단 뷰에서 날짜와 버튼이 양쪽으로 나눠져야하므로 justifyContent: 'space-between'을 주었다.

<View style={{backgroundColor: '#fff', borderRadius: 10, marginTop: 10, padding: 10, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 5}}>
    <View>
        <Text style={{fontSize: 18, marginBottom: 5}}>내용 들어갈 부분</Text>
    </View>
    <View style={{flexDirection: 'row', justifyContent: 'space-between'}}>
        <View>
            <Text style={{color: '#aaa'}}>날짜 들어갈 부분</Text>
        </View>
        <View style={{flexDirection: 'row'}}>
            <TouchableOpacity>
                <Text style={{marginRight: 5}}>Done?</Text>
            </TouchableOpacity>
            <TouchableOpacity>
                <Text>Delete</Text>
            </TouchableOpacity>
        </View>
    </View>
</View>
slec
6개월, 3주전

저랑도좀더친해지시죠

baealex
6개월, 3주전

@slec 😍😍😍

댓글을 작성하기 위해 로그인이 필요합니다.