|

Android ConstraintLayout 완전 정리 (2) – ConstraintLayout start end top bottom 제약 정리: View를 원하는 위치에 붙이는 법

Android ConstraintLayout 완전 정리 (2) – ConstraintLayout start end top bottom 제약 정리: View를 원하는 위치에 붙이는 법
ConstraintLayout은 XML 코드와 실제 배치 결과를 같이 볼 때 이해가 빨라집니다.

ConstraintLayout start end 제약은 View의 가로 위치를 정하는 기본 규칙입니다. 여기에 top, bottom 제약을 함께 걸어야 View의 세로 위치까지 안정적으로 정해집니다.

이번 글은 parent 기준 배치와 sibling 기준 배치를 나누어 보고, 같은 View가 어떤 제약을 만나면 어디로 이동하는지 이미지로 확인합니다.

ConstraintLayout start end top bottom 제약 방향 예시
각 제약은 View의 한쪽 edge를 다른 기준 edge에 연결합니다.

ConstraintLayout start end top bottom 제약은 두 부분으로 읽는다

예를 들어 layout_constraintStart_toStartOf는 두 부분으로 나눠 읽으면 쉽습니다. 앞의 Start는 내 View의 start edge입니다. 뒤의 StartOf는 대상 View의 start edge입니다.

  • layout_constraintStart_toStartOf: 내 start를 대상 start에 연결
  • layout_constraintStart_toEndOf: 내 start를 대상 end에 연결
  • layout_constraintEnd_toStartOf: 내 end를 대상 start에 연결
  • layout_constraintEnd_toEndOf: 내 end를 대상 end에 연결
  • top/bottom도 같은 방식으로 읽는다

속성 이름이 길어 보이는 이유는 “내 쪽 edge”와 “대상 쪽 edge”를 한 이름에 모두 담기 때문입니다. 그래서 속성을 외우기보다 왼쪽 절반과 오른쪽 절반을 나눠 읽으면 실수가 줄어듭니다.

  • constraintStart: 내 View의 start edge
  • toEndOf: 대상 View의 end edge
  • @id/nameText: 연결 대상
  • parent: ConstraintLayout 자체

parent 왼쪽 위에 붙이기

가장 기본은 View를 parent의 start와 top에 연결하는 것입니다. 이때 parent는 ConstraintLayout 자체입니다.

<Button
    android:id="@+id/saveButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Save"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

이 코드는 saveButton의 왼쪽 시작점을 parent의 시작점에 붙이고, saveButton의 위쪽을 parent의 위쪽에 붙입니다. margin이 없다면 parent의 기준선에 바로 붙습니다.

ConstraintLayout parent start top end bottom 배치 예시
parent 기준 제약은 화면 모서리나 가장자리 배치의 기본입니다.

parent 오른쪽 아래에 붙이기

반대로 end와 bottom을 parent에 연결하면 View는 오른쪽 아래 기준으로 배치됩니다. floating button이나 하단 액션 버튼을 만들 때 자주 보는 형태입니다.

<Button
    android:id="@+id/actionButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Action"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintBottom_toBottomOf="parent" />

여기서 end는 오른쪽이라고만 외우지 않는 편이 좋습니다. 언어 방향에 따라 start와 end의 실제 방향은 달라질 수 있습니다.

ConstraintLayout parent start top end bottom 배치 예시
parent 기준 제약은 화면 모서리나 가장자리 배치의 기본입니다.

이 예제는 실제 앱에서 화면 오른쪽 아래 버튼을 만들 때 자주 쓰입니다. 보통 여기에 marginEnd와 marginBottom을 함께 넣어 parent 가장자리와 버튼 사이에 여백을 둡니다.

<Button
    android:id="@+id/actionButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginEnd="24dp"
    android:layout_marginBottom="24dp"
    android:text="Action"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintBottom_toBottomOf="parent" />

A 오른쪽에 B 배치하기

sibling 기준 배치는 ConstraintLayout을 쓰는 이유가 가장 잘 드러나는 부분입니다. B의 start를 A의 end에 연결하면 B는 A 오른쪽에 놓입니다.

<TextView
    android:id="@+id/labelText"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="이름"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

<TextView
    android:id="@+id/valueText"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="병섭"
    app:layout_constraintStart_toEndOf="@id/labelText"
    app:layout_constraintTop_toTopOf="@id/labelText" />

이 구조에서는 labelText가 움직이면 valueText도 함께 움직입니다. valueText의 기준이 parent가 아니라 labelText이기 때문입니다.

ConstraintLayout sibling start_toEndOf 배치 예시
sibling 기준 제약은 한 View를 다른 View의 옆이나 아래에 붙일 때 사용합니다.

A 아래에 B를 놓을 때도 원리는 같습니다. 이번에는 B의 top을 A의 bottom에 연결합니다. start는 parent에 연결할 수도 있고, A의 start에 맞출 수도 있습니다.

<TextView
    android:id="@+id/descriptionText"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Description"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@id/titleText" />
ConstraintLayout sibling top_toBottomOf 세로 배치 예시
세로 배치는 top과 bottom edge의 연결 관계로 읽습니다.

가로로 붙일 때는 start/end를 봅니다. 세로로 붙일 때는 top/bottom을 봅니다. 이 기준만 분리해도 XML을 읽는 속도가 빨라집니다.


양쪽 제약을 걸면 가운데 배치가 된다

View의 start와 end를 모두 parent에 연결하면 ConstraintLayout은 View를 두 제약 사이에 놓습니다. 기본값은 가운데입니다. 나중에 bias를 배우면 이 위치를 왼쪽이나 오른쪽으로 밀 수 있습니다.

<Button
    android:id="@+id/centerButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Center"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintTop_toTopOf="parent" />
ConstraintLayout 양쪽 제약으로 가운데 배치하는 예시
양쪽 제약은 정렬 기준이 되고, 위치 조절은 bias로 이어집니다.

양쪽 제약은 “가운데 정렬 속성”이 아니라 “두 기준 사이에 놓기”에 가깝습니다. 기본 bias가 0.5라서 가운데로 보일 뿐입니다. 6편에서 bias를 바꾸면 같은 양쪽 제약에서도 왼쪽이나 오른쪽으로 치우칠 수 있습니다.


start/end를 먼저 쓰는 이유

left/right 속성도 있지만 새 글과 새 예제에서는 start/end를 기본으로 쓰는 편이 안전합니다. start/end는 레이아웃 방향을 고려합니다. 영어와 한국어 화면에서는 start가 보통 왼쪽이지만, RTL 언어에서는 반대가 될 수 있습니다.

ConstraintLayout start end와 left right RTL 차이 예시
start/end는 화면 방향이 바뀌는 언어 환경까지 고려한 제약입니다.

left/right가 항상 틀린 것은 아닙니다. 다만 새 화면을 만들 때는 start/end를 기본값으로 잡는 편이 더 안전합니다. 특히 다국어 앱이나 라이브러리 UI를 만들 때는 방향성 대응을 초반부터 고려하는 것이 좋습니다.


제약을 읽는 순서

복잡한 XML을 볼 때는 모든 속성을 위에서 아래로 읽지 않아도 됩니다. 먼저 가로 제약을 찾고, 그 다음 세로 제약을 찾습니다. 마지막으로 margin과 width/height를 확인합니다.

  1. 1단계: start/end 또는 left/right를 찾아 가로 위치를 본다
  2. 2단계: top/bottom 또는 baseline을 찾아 세로 위치를 본다
  3. 3단계: margin이 기준선에서 얼마나 떨어뜨리는지 본다
  4. 4단계: width/height가 wrap_content인지 0dp인지 확인한다

정리

ConstraintLayout 제약은 길게 외우지 않아도 됩니다. 내 View의 어느 edge를 대상의 어느 edge에 연결하는지만 읽으면 됩니다. parent 기준 배치로 시작하고, sibling 기준 배치를 익히면 실제 화면을 구성하는 감각이 생깁니다.

  • start/end는 가로 방향의 기본
  • top/bottom은 세로 방향의 기본
  • parent는 ConstraintLayout 자신
  • sibling 기준 제약은 실제 UI 조합에서 자주 사용
  • 양쪽 제약은 bias와 0dp 크기 계산의 기반

기본 제약을 한 번에 넓게 훑고 싶다면 기존에 정리한 안드로이드 ConstraintLayout 완전 정리 글도 참고할 수 있습니다. 이 시리즈에서는 그 내용을 더 잘게 나누어 이미지 중심으로 다시 설명합니다.

아래에는 이 편보다 앞에서 다룬 글만 모았습니다. 아직 뒤 편은 발행 전이므로 링크하지 않습니다.

공식 기준은 Android Developers ConstraintLayout 가이드AndroidX ConstraintLayout 레퍼런스를 확인했습니다.

함께보면 좋은 글