FlexboxLayout 뜯어보기

부모 레이아웃의 넓이에 따라 자식 뷰의 행을 동적으로 맞출 수 있는 레이아웃을 소개하겠습니다. 태그 목록을 구현할 때 가장 많이 쓰이지 않을까 싶습니다. 크기가 서로 다른 태그를 정해진 넓이에 따라 자동으로 행을 바꿔서 배치를 원하는 경우 안드로이드에서 기본으로 제공되는 레이아웃으로는 불가능합니다.

ConstraintLayout? 불가능.
자식 뷰들 간의 밀접한 관계 구성으로 이미 정해진 자식 뷰의 개수와 넓이인 경우에는 배치가 쉽지만, 새로운 항목이 추가되거나 제거되는 동적인 환경에서는 사용하기가 어렵습니다. 목록이 많아지는 경우 스크롤되지 않으며 자식 뷰의 크기가 줄어들어 적합하지 않습니다.

RelatveLayout? 불가능.
ConstraintLayout와 동일한 구조적인 문제로 적합하지 않습니다.

GridLayout? 확실 구현불가능.
각 행에 표시될 항목의 기본 개수를 지정해야 하기 때문에 자식 뷰의 넓이에 따라 동적으로 행의 개수를 가져야 하는 것과 너무 동떨어 지기 때문에 GridLayout도 적합하지 않습니다.

LinearLayout? 최선의 선택은 아니지만 구현은 가능.
ScrollView와 같이 조합하여 수동으로 구현할 수 있습니다. 부모 레이아웃의 넓이를 가져와 자식 뷰를 하나씩 추가하면서 행을 언제 바꿔야 할지 수동으로 구현하는 방법을 생각할 수 있습니다. 이미 Github에 TagView 등이 이런 방식을 채택하고 있습니다.

FlexboxLayout?

위의 LinearLayout으로 구현하기 위해 사용한 중첩 구조를 완벽하게 피 할 수 있으면서 원하는 구조를 짤 수 있었습니다.

dependencies {
   compile 'com.google.android:flexbox:0.3.0-alpha2'
}

FlexboxLayout을 사용하기 위해 build.gradle에 추가합니다. FlexLayout의 wrap속성을 사용하면 ViewGroup내의 자식 뷰들이 자동으로 다음 줄로 이동합니다. GridLayout의 행에 고정된 항목이 아닌 행 별로 다른 넓이를 가질 수 있도록 항목이 가변적일 수 있음을 의미합니다. FlexboxLayout은 RecyclerView와 함께 사용하여 스크롤을 자동으로 처리할 수 있습니다.

<com.google.android.flexbox.FlexboxLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:flexwrap="wrap”/>

화면에 모두 표시된다면 위의 코드로는 문제가 없습니다. 하지만 아이템이 너무 많아서 스크롤되어야 한다면 ScrollView에서 FlexboxLayout을 구현하는 것보다 RecyclerView를 이용하는 것이 성능이나 메모리면에서 훨씬 더 많은 이점이 있습니다.

RecyclerView에서 FlexboxLayout을 사용하기 위해서는 FlexboxLayoutManager를 사용하면 됩니다.

<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"
app:layoutManager="com.google.android.flexbox.FlexboxLayout”/>

레이아웃에서 layoutManager속성을 FlexboxLayout을 주면 됩니다. 하지만 코드에서 FlexboxLayout의 flexWrap속성을 wrap값로 변경해야 합니다.

그렇기 때문에 레이아웃에서 layoutManager를 바로 주는 것보다 아래와 같이 코드를 통해 RecyclerView의 layoutManager를 설정하는 게 좋습니다.

FlexboxLayoutManager layoutManager = new FlexboxLayoutManager();
layoutManager.setFlexWrap(FlexWrap.WRAP);
recyclerView.setLayoutManager(layoutManager);

 

flexGrow 속성은 LinearLayout의 weight와 같은 속성으로 작동합니다. 이렇게 하면 각 행의 나머지 공간을 균등한 공간으로 채울 수 있습니다.

FlexboxLayoutManager.LayoutParams flexboxLayoutParams = 
        (FlexboxLayoutManager.LayoutParams) mImageView.getLayoutParams();
flexboxLayoutParams.setFlexGrow(1.0f);

 

이 외에도 alignItem 속성은 아이템의 정렬되는 기준선을 설정 할 수 있으며, justifyContent를 이용하면 컨텐츠 배치를 설정 할 수 있습니다.

layoutManager.setAlignItems(AlignItems.BASELINE);
layoutManager.setJustifyContent(JustifyContent.CENTER);

 

물론 layout 속성에서도 추가 할 수 있습니다. FlexboxLayout을 활용 하면 다음과 같은 멋진 이미지 뷰어도 만들 수 있습니다.

 

참고:
https://blog.devcenter.co/unboxing-the-flexboxlayout-a7cfd125f023#.wyye4dtld