[Android] LinearLayout : 수평 또는 수직 정렬을 위한 레이아웃



 


예전에 ConstraintLayout과 LinearLayout에 대해서 간단하게 글을 써본 적이 있는데 글을 다시 쓰게 되었습니다. 공부를 하면서 쓴 글이라 너무 대충 적기도 한 것 같고, 좀 더 자세하게 정리하고 싶었거든요. 거기다 예전부터 많이 사용해왔던 다른 레이아웃들도 묶어서 정리해보고 싶었습니다. 그래서 자주 사용하는 4가지 레이아웃 (LinearLayout, RelativeLayout, FrameLayout, ConstraintLayout)을 각각 포스팅하고자 합니다.

다만 예전에 비해 ConstraintLayout을 사용하는 빈도가 높아졌고, 구글에서도 다른 레이아웃보다 ConstraintLayout을 권장한다고 하는군요. 물론 다른 레이아웃들이 아예 사용 안하는 것도 아니고, 오래된 프로젝트에서는 아직도 사용하는 경우가 있다고 합니다. 무엇보다 특정 상황에서는 그에 맞는 레이아웃을 사용하는 것이 좀 더 편할 때도 있구요. 그래서 모른 채로 넘어갈 수는 없습니다. 따라서 다른 레이아웃들은 어떤 개념인지, 어떻게 사용하는지 아주 간단하게만 짚고 넘어가고, ConstraintLayout을 좀 더 중점적으로 다뤄보겠습니다. 그럼 시작해볼까요?




LinearLayout

LinearLayout은 선형으로 View를 배치할 때 사용하는 레이아웃으로 직관적이라는 장점이 있습니다. 우리가 앱을 사용하면서 흔히 볼 수 있는 리스트나, 그리드같은 것들을 LinearLayout으로 표현할 수도 있습니다. 물론 RecyclerViewGridView가 그 자리를 대체하기 때문에 실제로 LinearLayout으로 해당 뷰들을 표현하는 경우는 많지 않습니다.

사용법은 아주 간단합니다. 그냥 layout에서 xml 디자인 위에 끌어다 놓으면 끝입니다. orientation 설정에 따라 자식 뷰들이 수직으로 정렬될 지, 수평으로 정렬될 지만 결정해주면 됩니다. 

대신 아래의 그림처럼 뷰가 다닥다닥 붙어 있는 모습이 보기 좋지 않으니, 각 자식 뷰들의 margin 등의 속성을 잘 만져주시는 것이 좋습니다. 그렇기 때문에 어떤 리스트와 같이 자식 뷰가 많은 레이아웃 형태를 만들기에는 조금 부담스러운 편이구요. 대신 아주 간단한 테이블의 형태 등을 빠르게 표현하기엔 좋다고 생각합니다. (대신 나중에 유지보수가 힘들어지는 것은 개발자가 감당해야겠죠?)


<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <LinearLayout
        android:id="@+id/linearLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintTop_toTopOf="parent">

        <Button
            android:id="@+id/button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Button" />

        <Button
            android:id="@+id/button2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Button" />

        <Button
            android:id="@+id/button3"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Button" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintTop_toBottomOf="@+id/linearLayout">

        <Button
            android:id="@+id/button4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Button" />

        <Button
            android:id="@+id/button5"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Button" />

        <Button
            android:id="@+id/button6"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Button" />
    </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>



WeightSum

LinearLayout에서 한번 생각해보고 넘어갈 만한 주제는, 자식 뷰의 크기가 다를 때 각각 공간을 어떻게 적절하게 할당할 수 있느냐 정도인데요, 이 때는 weightSum을 사용해야 합니다. LinearLayout에 weightSum 만큼의 공간을 주고 각 자식 뷰들에게 그 공간 중에 몇% 만큼의 비율을 할당할지를 결정하는 것입니다. 

아래의 사진은 위에 예시로 든 2개의 LinearLayout에서 weightSum만 적용한 모습입니다. (색상이나 margin 등의 세부 속성은 넘어가겠습니다.) 아래의 xml 파일을 보면 LinearLayout에는 weightSum을 주고, 각 뷰에 layout_weight 값을 주었습니다.

위의 vertical LinearLayout같은 경우 weightSum = 12 에 각 자식 뷰에 layout_weight = 2, 3, 7 만큼 준 모습이네요. 즉 12 만큼의 공간에 첫번째 뷰는 2 만큼을, 두번째 뷰는 3 만큼을, 세번째 뷰는 7 만큼의 공간을 가지고 있는 것입니다. 즉 2 : 3 : 7 이라는 얘기죠. 이 때 주의할 점이 2가지 있습니다.

1. 비율 잘 맞춰주기

2 + 3 + 7 = 12 입니다. 즉 각 뷰들의 layout_weight의 합이 weightSum 과 같지 않으면 비율이 이상하게 나오거나, 의미 없는 공간을 가지거나, 뷰가 잘려서 나오거나 등의 문제가 발생할 수 있습니다. 물론 상황에 따라 크게 문제가 없는 경우가 있을 수도 있지만 가급적이면 맞춰주는 것이 좋겠죠.

2. width 또는 height을 0dp로 설정

vertical LinearLayout의 자식 뷰는 코드처럼 height을 0dp로 맞춰주고, horizontal LinearLayout의 자식 뷰는 width를 0dp로 맞춰줘야 합니다. "이 자식 뷰들은 높이 (또는 너비)를 LinearLayout의 비율에 따라 정하겠다" 라는 의미가 됩니다.


<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <LinearLayout
        android:id="@+id/linearLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="10dp"
        android:weightSum="12"
        app:layout_constraintTop_toTopOf="parent">

        <Button
            android:id="@+id/button"
            android:layout_width="match_parent"
            android:height="0dp"
            android:backgroundTint="@color/teal_200"
            android:layout_height="0dp"
            android:layout_weight="2"/>

        <Button
            android:id="@+id/button2"
            android:layout_width="match_parent"
            android:height="0dp"
            android:backgroundTint="@color/teal_200"
            android:layout_height="0dp"
            android:layout_weight="3"/>

        <Button
            android:id="@+id/button3"
            android:layout_width="match_parent"
            android:height="0dp"
            android:backgroundTint="@color/teal_200"
            android:layout_height="0dp"
            android:layout_weight="7"/>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:padding="10dp"
        android:weightSum="10"
        app:layout_constraintTop_toBottomOf="@+id/linearLayout">

        <Button
            android:id="@+id/button4"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginHorizontal="2dp"
            android:layout_weight="1" />

        <Button
            android:id="@+id/button5"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginHorizontal="2dp"
            android:layout_weight="2" />

        <Button
            android:id="@+id/button6"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginHorizontal="2dp"
            android:layout_weight="7" />
    </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>





마치며.. 

LinearLayout을 동적으로 불러와서 addView로 자식 뷰를 붙이는 방법도 있지만, 개인적으로는 LinearLayout을 이런 식으로 사용하는 것은 별로 좋지 않다고 생각합니다. 코드로 뷰 형태를 구성하는 단계가 된다면 차라리 RecyclerView나 GridView를 사용하는 것이 더 좋다고 생각하기 때문입니다. 일단 제가 예전에 그런 식으로 프로젝트를 진행했는데, 유지보수가 말도 안되게 어렵습니다. 따라서 권장하지 않습니다.

그래서 LinearLayout을 사용하는 데에 크게 무리는 없을 만한 것들을 간단하게 적어봤습니다. 물론 속성 등에 대해선 직접 찾아보고 적용해보는 것이 좋습니다. 워낙 방대하기 때문에... 그래도 다른 뷰를 다뤄봤다면 어려운 내용은 없을 것입니다. 구글 공식 문서 등에도 잘 나와 있구요.

이제 3개 (RelativeLayout, FrameLayout, ConstraintLayout) 남았네요. 이것들도 계속 다뤄보겠습니다. 





 





댓글