Study Record

[안드로이드] ConstraintLayout 살펴보기 본문

안드로이드

[안드로이드] ConstraintLayout 살펴보기

초코초코초코 2023. 6. 17. 18:42
728x90

😶 ConstraintLayout

ConstraintLayout 은 평면 보기 계층 구조가 있는 크로 복잡한 레이아웃을 만들 수 있는 ViewGroup 에 속한다. 하위 뷰들 간의 연결 또는 정렬(제약 조건) 이 존재하며, 뷰마다 하나 이상의 수평, 수직 제약 조건을 정의해야 한다.

 

 

😶 기본

ConstraintLayout 을 ViewGroup 으로 갖는 모든 View 는 수평, 수직 제약 조건을 하나씩 정의해야 한다. 제약 조건을 부여하는 방법은 app:layout_constraint[방향]_to[방향]Of 속성으로 값은 "parent" 혹은 같은 하위 요소의 id 값으로 한다. "parent" 는 부모 ConstraintLayout 를 의미한다.(즉, 오른쪽 끝, 왼쪽 끝, 맨 상단, 맨 하단)

 

[방향] 에는 bottom, start, end, top 중 4가지 값을 가질 수 있는데 start 와 end 는 언어를 읽을 때 시작 방향이 오른쪽이면 start 가 오른쪽이 되고, 읽는 방향의 시작이 왼쪽이면 start 는 왼쪽이 된다. 한국어에서는 start 가 왼쪽, end 가 오른쪽이다.

 

app:layout_constraint[방향1]_to[방향2]of 에서 [방향1]은 자기 자신이고 [방향2]는 제약을 걸 상대라고 생각하면 된다. 예를 들어, app:layout_constraintStart_toEndOf="parent" 이면 수평 제약은 왼쪽 벽이 된다. [방향1] 과 [방향2] 는 같은 수평 또는 수직상에서만 가능하다. app:layout_constraintStart_toBottomOf 는 불가능하다.

 

 

예시) 

<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">

    <TextView
        android:id="@+id/view1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        ...
        android:text="Hello World!"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/view2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="20dp"
        ...
        android:text="Hello World!"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/view1"/>


</androidx.constraintlayout.widget.ConstraintLayout>

 

view1 의 수평 조건은 오른쪽 벽과 왼쪽 벽에 위치해야 하니 그 중간의 가운데로 위치된 것이고, 수직 조건은 위쪽 벽에 붙어야 하므로 상단에 위치해 있다.

view2 의 수평 조건은 view1 과 같이 오른쪽 벽과 왼쪽 벽에 위치하는데 너비의 크기가 "0dp" 이니까 늘릴 수 있을 만큼 너비 크기가 늘어난다. view2 의 수직조건은 자기 자신의 위쪽(Top)이 상대(view1)의 아래쪽(Bottom)에 붙어야 하므로 view1 의 아래에 위치한다. 

 

 

 

😶 chain

View 끼리 서로를 제약 조건을 걸면 chain 이 생성될 수 있다. 이렇게 서로 체인이 맺어지면 Head 에서 체인 속성을 정할 수 있는데 다음 보기와 같은 수평적 체인은 add:layout_constraintHoriaontal_chainStyle , 수직적 체인은 add:layout_constraintVertical_chainStyle 으로 정할 수 있다.

 

 

 

체인 종류 - spread , spread_inside , 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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:theme="@style/NameStyle"
    tools:context=".MainActivity">

    <View
        android:id="@+id/container"
        android:layout_width="160dp"
        android:layout_height="200dp"
        android:background="@color/gray"
        android:layout_margin="20dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


    <TextView
        android:id="@+id/text_view_1"
        android:layout_width="0dp"
        android:layout_height="30dp"
        android:text="textView1"
        android:background="@color/purple_200"
        android:layout_marginHorizontal="20dp"
        app:layout_constraintVertical_chainStyle="spread"
        app:layout_constraintBottom_toTopOf="@+id/text_view_2"
        app:layout_constraintStart_toEndOf="@+id/container"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="@+id/container"/>

    <TextView
        android:id="@+id/text_view_2"
        android:layout_width="0dp"
        android:layout_height="30dp"
        android:text="textView2"
        android:background="@color/purple_200"
        android:layout_marginHorizontal="20dp"
        app:layout_constraintBottom_toTopOf="@+id/text_view_3"
        app:layout_constraintTop_toBottomOf="@+id/text_view_1"
        app:layout_constraintStart_toEndOf="@+id/container"
        app:layout_constraintEnd_toEndOf="parent"/>

    <TextView
        android:id="@+id/text_view_3"
        android:layout_width="0dp"
        android:layout_height="30dp"
        android:text="textView3"
        android:background="@color/purple_200"
        android:layout_marginHorizontal="20dp"
        app:layout_constraintBottom_toBottomOf="@+id/container"
        app:layout_constraintStart_toEndOf="@+id/container"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/text_view_2" />



</androidx.constraintlayout.widget.ConstraintLayout>

 

 

 

😶 가중치

서로 체인으로 연결된 상태에서 수직 체인일 경우, app:layout_constraintVertical_weight (가중치)를 사용하고 높이를 0dp 로 주면 연결된 체인의 가중치에 따라 높이가 결정된다.

 

수평 체인일 경우, app:layout_constraintHorizontal_weight 속성은 너비를 0dp 로 주면 각각 가중치 값에 따라 너비가 결정된다.

 

 

예시) textView1 : textView2 : textView3 = 2 : 2 : 1 의 가중치를 가질 경우

<?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">

    <View
        android:id="@+id/container"
        android:layout_width="160dp"
        android:layout_height="200dp"
        android:background="@color/gray"
        android:layout_margin="20dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


    <TextView
        android:id="@+id/text_view_1"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:text="textView1"
        android:background="@color/purple_500"
        android:layout_marginHorizontal="20dp"
        app:layout_constraintVertical_weight="2"
        app:layout_constraintBottom_toTopOf="@+id/text_view_2"
        app:layout_constraintStart_toEndOf="@+id/container"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="@+id/container"/>

    <TextView
        android:id="@+id/text_view_2"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:text="textView2"
        android:background="@color/purple_200"
        android:layout_marginHorizontal="20dp"
        app:layout_constraintVertical_weight="2"
        app:layout_constraintBottom_toTopOf="@+id/text_view_3"
        app:layout_constraintTop_toBottomOf="@+id/text_view_1"
        app:layout_constraintStart_toEndOf="@+id/container"
        app:layout_constraintEnd_toEndOf="parent"/>

    <TextView
        android:id="@+id/text_view_3"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:text="textView3"
        android:background="@color/teal_200"
        android:layout_marginHorizontal="20dp"
        app:layout_constraintVertical_weight="1"
        app:layout_constraintBottom_toBottomOf="@+id/container"
        app:layout_constraintStart_toEndOf="@+id/container"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/text_view_2"/>



</androidx.constraintlayout.widget.ConstraintLayout>

 

 

 

😶 bias

서로 "packed" 로 연결된 체인에서 app:layout_constraintVertical_bias (수직 체인) 혹은 app:layout_constraintHorizontal_bias (수평 체인) 를 사용하면 편향된 위치를 조절할 수 있다. 값은 0 ~1 로 설정할 수 있고 0 이면 start(상단) 에 위치하고 1 이면 end(하단) 에 위치한다.

 

체인뿐만 아니라 수직적으로 또는 수평적으로 제약 관계를 가지고 있을 때 bias 를 설정하지 않을 땐 관계를 맺은 요소의 가운데에 위치한다. 하지만 bias 를 설정하면 가운데뿐만 아니라 편향된 위치를 가지게 할 수 있다. (ex. 가운데는 0.5 , 상단은 0 , 하단은 1 등등)

 

 

예시)

<?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"
    android:theme="@style/NameStyle"
    tools:context=".MainActivity">

    <View
        android:id="@+id/container"
        android:layout_width="160dp"
        android:layout_height="300dp"
        android:background="@color/gray"
        android:layout_margin="20dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


    <TextView
        android:id="@+id/text_view_1"
        android:layout_width="0dp"
        android:layout_height="40dp"
        android:text="textView1"
        android:background="@color/purple_500"
        android:layout_marginHorizontal="20dp"
        app:layout_constraintVertical_bias="0.7"
        app:layout_constraintVertical_chainStyle="packed"
        app:layout_constraintBottom_toTopOf="@+id/text_view_2"
        app:layout_constraintStart_toEndOf="@+id/container"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="@+id/container"/>

    <TextView
        android:id="@+id/text_view_2"
        android:layout_width="0dp"
        android:layout_height="40dp"
        android:text="textView2"
        android:background="@color/purple_200"
        android:layout_marginHorizontal="20dp"
        app:layout_constraintBottom_toTopOf="@+id/text_view_3"
        app:layout_constraintTop_toBottomOf="@+id/text_view_1"
        app:layout_constraintStart_toEndOf="@+id/container"
        app:layout_constraintEnd_toEndOf="parent"/>

    <TextView
        android:id="@+id/text_view_3"
        android:layout_width="0dp"
        android:layout_height="40dp"
        android:text="textView3"
        android:background="@color/teal_200"
        android:layout_marginHorizontal="20dp"
        app:layout_constraintBottom_toBottomOf="@+id/container"
        app:layout_constraintStart_toEndOf="@+id/container"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/text_view_2"/>

</androidx.constraintlayout.widget.ConstraintLayout>

 

 

😶 BaseLine 제약 조건

BaseLine 제약 조건은 보기 텍스트의 기준선을 다른 보기 텍스트의 기준선과 정렬한다. 텍스트가 포함된 뷰를 위치시킬 때 기준선을 사용하지 않으면 텍스트가 서로 이어지지 않은 것처럼 보일 수 있다.

 

 

 

다음 예시로 "how" 는 글씨가 크고 "small textView" 는 글씨가 작은 텍스트 뷰로 "how" 를 "small textView" 의 bottom 에 맞췄을 때는 "small textView" 가 아래쪽인 것처럼 보이고 "how" 가 상단과 하단을 연결해 가운데에 위치하면 "small textView" 가 살짝 떠있는 것처럼 보인다.

 

 

예시) 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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="20dp"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/label_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="how"
        android:textSize="35sp"
        android:textStyle="bold"
        app:layout_constraintBaseline_toBaselineOf="@+id/info_text"
        app:layout_constraintStart_toStartOf="parent" />

    <TextView
        android:id="@+id/info_text"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="  small textView"
        android:gravity="start"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toEndOf="@+id/label_text" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

 

😶 가이드 라인 이용하기

화면을 꾸미기 전에 가이드 라인(선)을 미리 그려놓고 그 기준에 맞게 하위 요소들을 배치시킬 수도 있다. orientation 속성으로 가로선 혹은 세로선인지 정하고 layout_constraintGuide_percent로 start(ex. 상단 or 왼쪽) 으로부터 어디로 위치할지 0 ~ 1 사이값으로 위치시킬 수 있다.

 

가이드라인은 실제 화면에 보이는 요소가 아니다. 다른 요소를 배치시키기 위한 도구일 뿐이다.

 

다음 예시의 가이드라인은 딱 정 중앙에 가로선의 가이드라인이다.

<androidx.constraintlayout.widget.Guideline
    android:id="@+id/gl_width_line"
    android:layout_width="1dp"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    app:layout_constraintGuide_percent=".5" />

 

app:layout_constraintGuide_begin 은 시작점(보통 상단 혹은 왼쪽) 에서부터 얼마만큼 떨어졌는지로 가이드라인을 위치시킬 수 있다. (app:layout_constraintGuide_end 는 끝점(하단 혹은 오른쪽)에서 떨어진 거리)

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

 

 

예시) 가로선, 세로선이 포함된 화면

<?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">

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/gl_width_line"
        android:layout_width="wrap_content"
        android:layout_height="1dp"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent=".5" />


    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/gl_height_line"
        android:layout_width="1dp"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent=".8" />

    <TextView
        android:id="@+id/label_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="how"
        android:textSize="35sp"
        android:textStyle="bold"
        app:layout_constraintBaseline_toBaselineOf="@+id/info_text"
        app:layout_constraintEnd_toStartOf="@+id/info_text"/>

    <TextView
        android:id="@+id/info_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="  small textView"
        android:gravity="start"
        app:layout_constraintBottom_toTopOf="@+id/gl_width_line"
        app:layout_constraintEnd_toEndOf="@+id/gl_height_line" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

 

😶 너비, 높이 비율로 설정하기

너비, 높이의 비율로 요소를 그리고 싶다면 app:layout_constraintDimensionRatio 속성을 사용할 수 있다. 

너비와 높이 둘 중 하나가 "0dp"(match_parent) 로 설정하거나 둘 다 "0dp" 로 설정해야 한다.

 

app:layout_constraintDimensionRatio="1:1" 과 같은 형식으로 사용할 수 있는데 기본적으로 "width:height" 비율이다. 1:1 이면 가로와 세로의 길이가 동일한 요소를 그릴 수 있다. 

 

app:layout_constraintDimensionRatio="H,3:7" 과 같이 앞의 "H" 와 "W" 가 붙을 수 있는데 "H" 면 높이를 제약한다는 의미이고 "W" 면 너비를 제약한다는 의미이다. 만약 높이를 제약한다면 너비의 값이 정해진 상태에서 높이의 크기를 비율에 맞게 적용하겠다는 의미이고, 너비를 제약한다면 높이의 값이 정해진 상태에서 너비의 크기를 비율에 맞게 적용하겠다는 의미이다.

 

 

예시) 

<?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"
    android:padding="20dp"
    tools:context=".MainActivity">

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/gl"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.2"/>
    
    <View
        android:id="@+id/view1"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="@color/gray"
        app:layout_constraintDimensionRatio="H,6:1"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>

    <View
        android:id="@+id/view2"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="@color/gray"
        app:layout_constraintDimensionRatio="W,2:1"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@+id/gl"
        app:layout_constraintStart_toStartOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

view1 은 수평적으로 너비의 크기가 정해진 상태로 "H,6:1" 이므로 너비의 1/6 만큼 높이의 길이로 한다는 의미가 된다.

view2 는 수직적으로 높이의 크기가 정해진 상태로 "W,2:1" 이므로 높이의 2배만큼 너비의 길이로 한다는 의미가 된다. 

 

 

 

 

ConstraintLayout으로 반응형 UI 빌드  |  Android 개발자  |  Android Developers

컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. ConstraintLayout으로 반응형 UI 빌드   Android Jetpack의 구성요소 ConstraintLayout을 사용하면 플랫 뷰 계층 구조(중첩

developer.android.com

 

728x90