Android

Android ConstraintLayout 사용법

태인킴 2020. 10. 21. 01:07
반응형


1. 왜 ConstraintLayout을 쓰나요?

LinearLayout으로 Android의 UI를 그리게 되면 꽤 많은 중첩 Layout을 만들어 냅니다. 이렇게 많은 중첩 Layout은 Android가 화면 프레임을 그리는데 있어서 속도가 많이 느려집니다. RelativeLayout는 멀티 디바이스의 해상도의 따라서 대응하기가 힘듬니다. 따라서 ConstraintLayout 이 등장 했습니다. ConstraintLayout은 중첩된 Layout을 지양하고, flat Layout을 지향 합니다. flat Layout은 중첩된 Layout이 아닌, ConstraintLayout 1개의 layout 으로 구성된 Layout을 의미 합니다. ConstraintLayout 의 제약 조건을 이용하여 UI Component를 제어 하는 방식은 중첩된 Layout을 피할수 있도록 설계 되었습니다. 하지만, 경우의 따라서 몇번의 중첩된 Layout으로 사용하는 경우도 있습니다. 또는 include를 이용하여 사용하는 경우도 있습니다.

 

 

2. layout_constraintTop_toTopOf="parent"

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:layout_width="40dp"
        android:layout_height="40dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

 먼저, 위와 같은 attribute가 있습니다. 이 attribute의 결과 화면은 아래와 같습니다.

app:layout_constraintTop_toTopOf="parent" 이와 같은 속성은 오른쪽에서 붙어 읽어 주시면 편합니다. 해석 하면, "parent 부모의 Top 부분의 현재 버튼의 Top을 연결(제약 조건) 합니다."

app:layout_constraintLeft_toLeftOf="parent" 이와 같은 속성은 해석 하면, "parent 부모의 Left 부분의 현재 버튼의 Left을 연결(제약 조건) 합니다." 또한, 'parent' 대신에 '@+id/(컴포넌트 id명)' 을 사용하여 대상에 따라서 연결(제약 조건)을 걸어 줄수가 있습니다.

 

3. Left vs Start

Top, Bottom, Left, Right 모두 위와 같은 속성을 적용 할수 있습니다. 또한 Start, End 속성도 있는데요. 이는 화면 flow(LTR, RTL)에 따라서 Start = Left, End = Right 되기도 하고, Start = Right, End = Left 가 되기도 합니다. 저희는 주로 LTR layout을 사용하기 때문에, Start = Left, End = Right 라고 생각하시면 되겠습니다.

 

 

4. layout_constraintRight_toRightOf="parent"

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button1"
        android:layout_width="40dp"
        android:layout_height="40dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"/>

    <Button
        android:id="@+id/button2"
        android:layout_width="40dp"
        android:layout_height="40dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

버튼1과 버튼2의 Top을 모두 parent의 연결 시켜 주고, 버튼1은 parent 왼쪽, 버튼2는 parent 오른쪽의 연결 시켜준 모습 입니다.

 

 

5. layout_constraintRight_toRightOf="@+id/button1"

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button1"
        android:layout_width="40dp"
        android:layout_height="40dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"/>

    <Button
        android:id="@+id/button2"
        android:layout_width="40dp"
        android:layout_height="40dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toRightOf="@+id/button1"/>

</androidx.constraintlayout.widget.ConstraintLayout>

버튼2의 "app:layout_constraintLeft_toRightOf="@+id/button1"" 이 문장을 추가 시켜주어, 버튼2가 버튼1쪽으로 더 이동한 모습 입니다. 

 

 

6. 가운데 정렬

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button1"
        android:layout_width="40dp"
        android:layout_height="40dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/button2"/>

    <Button
        android:id="@+id/button2"
        android:layout_width="40dp"
        android:layout_height="40dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toRightOf="@+id/button1"/>

</androidx.constraintlayout.widget.ConstraintLayout>

 

버튼1의 "app:layout_constraintRight_toLeftOf="@+id/button2"" 이 문장을 추가시켜 주어 2개의 버튼을 가운데 정렬 시켰습니다. 이 문장을 추가 시켜 주므로써, 버튼1과 버튼2는 parent를 기준으로 왼쪽, 오른쪽 모두 균등한 힘으로 잡아 땡기기 때문에, 가운데 정렬이 되었습니다. 버튼이 연결된 모습을 보시면 가운데 선이 물결 또는 체인 모습으로 버튼1과 버튼2과 연결되어 있습니다. 이것을 'chain(체인)' 이라고 부릅니다. 이 체인을 제어하는 속성을 알아보도록 하겠습니다.

 

 

7. chain(체인) "spread_inside"

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button1"
        android:layout_width="40dp"
        android:layout_height="40dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintHorizontal_chainStyle="spread_inside"
        app:layout_constraintRight_toLeftOf="@+id/button2"/>

    <Button
        android:id="@+id/button2"
        android:layout_width="40dp"
        android:layout_height="40dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toRightOf="@+id/button1"/>

</androidx.constraintlayout.widget.ConstraintLayout>

 

버튼1의 app:layout_constraintHorizontal_chainStyle="spread_inside" 문장이 추가 되었습니다. 'spread_inside'는 그림과 같이 변합니다. chain 스타일은 default가 'spread' 속성 입니다.

 

 

8. chain(체인) "packed"

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button1"
        android:layout_width="40dp"
        android:layout_height="40dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintRight_toLeftOf="@+id/button2"/>

    <Button
        android:id="@+id/button2"
        android:layout_width="40dp"
        android:layout_height="40dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toRightOf="@+id/button1"/>

</androidx.constraintlayout.widget.ConstraintLayout>

 

버튼1의 app:layout_constraintHorizontal_chainStyle="packed" 문장이 추가 되었습니다. 'packed'는 그림과 같이 변합니다.

 

 

9. 0dp 활용법

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button1"
        android:layout_width="40dp"
        android:layout_height="40dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/button2"/>

    <Button
        android:id="@+id/button2"
        android:layout_width="40dp"
        android:layout_height="40dp"
        app:layout_constraintTop_toTopOf="@+id/button1"
        app:layout_constraintBottom_toBottomOf="@+id/button1"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toRightOf="@+id/button1"/>

</androidx.constraintlayout.widget.ConstraintLayout>

다시, chain 을 빼고, 버튼2의 app:layout_constraintTop_toTopOf="@+id/button1", 
app:layout_constraintBottom_toBottomOf="@+id/button1" 을 추가 시켜 줍니다. 따라서 버튼2는 버튼1의 Top, Bottom을 따라갈수 있습니다.

 

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button1"
        android:layout_width="40dp"
        android:layout_height="140dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/button2"/>

    <Button
        android:id="@+id/button2"
        android:layout_width="40dp"
        android:layout_height="0dp"
        app:layout_constraintTop_toTopOf="@+id/button1"
        app:layout_constraintBottom_toBottomOf="@+id/button1"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toRightOf="@+id/button1"/>

</androidx.constraintlayout.widget.ConstraintLayout>

 

 이제 버튼2의 Height을 0dp으로 변경, 버튼1의 Height를 140dp로 변경 하였습니다. 그러니 버튼2의 Top, Bottom이 버튼1의 Top, Bottom을 따라가는 것을 확인 할 수 있습니다. 0dp는 이런식으로 사용 할수 있습니다.

 

 

11. Guideline 활용법

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/vertical_guideline"
        app:layout_constraintGuide_begin="50dp"
        android:orientation="vertical"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    
    <Button
        android:id="@+id/button1"
        android:layout_width="40dp"
        android:layout_height="40dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/button2"/>

    <Button
        android:id="@+id/button2"
        android:layout_width="40dp"
        android:layout_height="40dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toRightOf="@+id/button1"/>

</androidx.constraintlayout.widget.ConstraintLayout>

이번에는, Guideline을 그려 보았습니다. Guideline 은 포토샵, 일러스트에서 디자인을 하기 전에 '가이드 라인'을 기준으로 전체 UI 컴포넌트 들의 마진이나, 디자인 영역을 잡을때 사용합니다. 이와 같은 역할로 Guideline을 지원 합니다. orientation을 설정하여 가로, 세로 가이드라인 을 그릴수 있습니다. app:layout_constraintGuide_begin="(왼쪽에서 부터 떨어진 길이)", app:layout_constraintGuide_end="(오른쪽에서 부터 떨어진 길이)"를 설정 할수 있습니다. 

 

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/left_vertical_guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_begin="50dp" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/right_vertical_guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_end="50dp" />

    <Button
        android:id="@+id/button1"
        android:layout_width="40dp"
        android:layout_height="40dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/button2"/>

    <Button
        android:id="@+id/button2"
        android:layout_width="40dp"
        android:layout_height="40dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toRightOf="@+id/button1"/>

</androidx.constraintlayout.widget.ConstraintLayout>

왼쪽, 오른쪽 모두 50dp 씩 떨어진 가이드 라인을 그렸습니다.

 

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/left_vertical_guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_begin="50dp" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/right_vertical_guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_end="50dp" />

    <Button
        android:id="@+id/button1"
        android:layout_width="40dp"
        android:layout_height="40dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="@+id/left_vertical_guideline"
        app:layout_constraintRight_toLeftOf="@+id/button2"/>

    <Button
        android:id="@+id/button2"
        android:layout_width="40dp"
        android:layout_height="40dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintRight_toRightOf="@+id/right_vertical_guideline"
        app:layout_constraintLeft_toRightOf="@+id/button1"/>

</androidx.constraintlayout.widget.ConstraintLayout>

버튼1, 버튼2의 left, right의 대상을 가이드라인으로 변경 하였습니다. 그러니, 그림과 같이 가이드 라인(50dp) 만큼의 마진이 생겼습니다. 직접 marginLeft, marginRight를 주어서 컴포넌트들을 옴길수 있지만, 대부분의 디자인의 좌우 마진은 같습니다. 따라서 위와 같은 Guideline(가이드 라인)을 그려서 모든 컴포넌트의 적용하면, 추후 좌,우 마진 변경 시의 한번의 변경 할수 있습니다. 또한, ConstraintLayout은 멀티 디바이스의 대응 할수 있도록 설계 되었다고 하였습니다. 가이드 라인 역시도, dp값이 아닌, app:layout_constraintGuide_percent="0.1" 을 사용하여, 퍼센트(%)로 작성 할수 있습니다.

 

 

12. 폰트 Baseline 맞추기

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/tv1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="text1"
        android:textSize="30sp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/tv2"/>

    <TextView
        android:id="@+id/tv2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="text2"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toRightOf="@+id/tv1"/>

</androidx.constraintlayout.widget.ConstraintLayout>

위와 같이 TextView1과 TextView2가 다른 폰트 사이즈로 존재 합니다. 이때 굉장히 유용한 속성이 있습니다.

 

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/tv1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="text1"
        android:textSize="30sp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/tv2"/>

    <TextView
        android:id="@+id/tv2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="text2"
        app:layout_constraintBaseline_toBaselineOf="@+id/tv1"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toRightOf="@+id/tv1"/>

</androidx.constraintlayout.widget.ConstraintLayout>

바로, app:layout_constraintBaseline_toBaselineOf="@+id/tv1"을 추가 하여, 글자 간의 baseline 위치를 맞출수 있습니다. 굉장히 유용한 기능 입니다. 이상, ConstraintLayout 사용법 이였습니다.

반응형