|

Android ConstraintLayout 완전 정리 (13) – ConstraintLayout Barrier 사용법: 텍스트 길이에 따라 동적 기준선 만들기

Android ConstraintLayout 완전 정리 (13) – ConstraintLayout Barrier 사용법: 텍스트 길이에 따라 동적 기준선 만들기
ConstraintLayout Barrier는 XML 코드와 동적 기준선 이미지를 함께 보면 이해가 빨라집니다.

ConstraintLayout Barrier는 텍스트 길이가 바뀌어도 View가 서로 겹치지 않게 만드는 동적 기준선입니다. Guideline이 화면의 고정 위치나 비율 위치를 기준으로 삼는다면, Barrier는 참조한 View들의 실제 위치를 기준으로 움직입니다.

이번 글에서는 ConstraintLayout Barrier를 “보이지 않는 선”이라는 말로만 끝내지 않겠습니다. 짧은 label, 긴 label, 여러 TextView, 버튼 배치, barrierDirection, constraint_referenced_ids, barrierAllowsGoneWidgets까지 실제 XML 예시와 이미지로 나눠 보겠습니다.


ConstraintLayout Barrier 핵심 정리

  • Barrier는 여러 View의 edge를 보고 만들어지는 동적 기준선입니다.
  • 참조 View는 app:constraint_referenced_ids로 지정합니다.
  • 기준 방향은 app:barrierDirection으로 정합니다.
  • 다른 View는 Barrier에 constraint를 걸 수 있습니다.
  • Guideline은 스스로 위치를 정하고, Barrier는 참조 View 위치에 따라 움직입니다.
ConstraintLayout Barrier 짧은 텍스트와 긴 텍스트에서 동적 기준선이 이동하는 이미지
Barrier는 참조 View의 실제 위치에 따라 기준선이 움직입니다.

ConstraintLayout Barrier가 필요한 순간

Barrier는 한 View의 위치가 아니라 여러 View 중 가장 멀리 나온 edge를 기준으로 다음 View를 배치하고 싶을 때 사용합니다. 대표적인 예가 label/value UI입니다. label 텍스트가 짧을 때는 문제가 없어 보이지만, 긴 텍스트나 다국어 문자열이 들어오면 value나 button이 label과 겹칠 수 있습니다.

공식 Android Developers 문서는 Barrier를 Guideline과 비슷한 보이지 않는 선으로 설명하되, Barrier는 자신의 위치를 직접 정의하지 않고 포함된 View 위치에 따라 움직인다고 설명합니다. 공식 기준은 Android Developers ConstraintLayout 가이드에서 확인했습니다.


Guideline으로 처리하면 왜 어색해질까

ConstraintLayout Barrier가 필요한 Guideline 고정 기준선 실패 예시
텍스트 길이가 핵심 변수라면 고정 Guideline은 실제 내용 끝을 따라가지 못합니다.

Guideline은 화면의 50% 지점, 시작 edge에서 24dp, 끝 edge에서 16dp처럼 먼저 위치가 정해지는 기준선입니다. 그래서 화면 분할이나 공통 여백에는 좋습니다. 하지만 텍스트가 길어질 때마다 기준선이 움직여야 하는 UI에는 맞지 않을 수 있습니다.

<androidx.constraintlayout.widget.Guideline
    android:id="@+id/valueGuideline"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    app:layout_constraintGuide_percent="0.5" />

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

<Button
    android:id="@+id/actionButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Edit"
    app:layout_constraintStart_toEndOf="@id/valueGuideline"
    app:layout_constraintTop_toTopOf="@id/labelText" />

이 구조의 문제는 Guideline 자체가 잘못됐다는 뜻이 아닙니다. 기준선 선택이 문제입니다. 텍스트 끝을 따라 움직여야 하는데 화면 50%라는 고정 기준을 사용했기 때문에, 긴 텍스트에서는 버튼과 내용의 관계가 어색해집니다.


Barrier로 바꾸면 기준선이 내용 뒤로 이동한다

ConstraintLayout Barrier가 여러 텍스트 중 가장 긴 View 끝을 기준으로 버튼을 배치하는 이미지
Barrier는 여러 참조 View 중 지정한 방향에서 가장 멀리 있는 edge를 기준으로 삼습니다.

Barrier는 참조한 View의 지정 방향 edge를 봅니다. 예를 들어 barrierDirection="end"로 두면 참조 View들의 end edge 중 가장 멀리 나온 위치가 Barrier 기준선이 됩니다. 버튼은 그 Barrier 뒤에 붙이면 됩니다.

<TextView
    android:id="@+id/nameText"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Name"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

<TextView
    android:id="@+id/descriptionText"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Long description"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@id/nameText" />

<androidx.constraintlayout.widget.Barrier
    android:id="@+id/textBarrier"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:barrierDirection="end"
    app:constraint_referenced_ids="nameText,descriptionText" />

<Button
    android:id="@+id/editButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Edit"
    app:layout_constraintStart_toEndOf="@id/textBarrier"
    app:layout_constraintTop_toTopOf="@id/nameText" />

이제 editButtonnameTextdescriptionText 중 더 오른쪽으로 긴 View 뒤에 배치됩니다. 텍스트가 짧으면 Barrier도 왼쪽에 있고, 텍스트가 길면 Barrier가 오른쪽으로 이동합니다.


여러 label 뒤에 value 시작선 맞추기

ConstraintLayout Barrier로 여러 label 뒤 value 시작 위치를 맞추는 폼 예시
여러 label 중 가장 긴 항목 뒤에 value들을 정렬할 때 Barrier가 자연스럽습니다.

실무에서는 label 하나가 아니라 여러 label 뒤에 value를 정렬해야 하는 경우가 많습니다. 예를 들어 이름, 전화번호, 이메일 label의 길이가 서로 다르면 value 시작 위치가 제각각이 되거나, 긴 label과 value가 겹칠 수 있습니다.

<TextView
    android:id="@+id/nameLabel"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Name" />

<TextView
    android:id="@+id/phoneLabel"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Phone Number" />

<TextView
    android:id="@+id/emailLabel"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Email" />

<androidx.constraintlayout.widget.Barrier
    android:id="@+id/labelEndBarrier"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:barrierDirection="end"
    app:constraint_referenced_ids="nameLabel,phoneLabel,emailLabel" />

이렇게 label들을 하나의 Barrier에 묶어두면 value View들은 labelEndBarrier의 end 쪽에 붙을 수 있습니다. 핵심은 “가장 긴 label이 무엇인지 미리 알 필요가 없다”는 점입니다.


barrierDirection은 무엇을 기준으로 볼지 정한다

ConstraintLayout Barrier barrierDirection start end bottom 방향 비교 이미지
barrierDirection은 참조 View들의 어느 방향 edge를 기준으로 삼을지 정합니다.

barrierDirection은 Barrier가 참조 View들의 어느 방향 edge를 볼지 정합니다. 왼쪽에서 오른쪽으로 읽는 화면이라면 label 뒤에 value를 붙일 때 보통 end를 많이 씁니다. 위아래 기준을 잡고 싶다면 top이나 bottom도 사용할 수 있습니다.

  • start: 참조 View들의 시작 edge 중 가장 바깥쪽 기준
  • end: 참조 View들의 끝 edge 중 가장 바깥쪽 기준
  • top: 참조 View들의 위쪽 edge 기준
  • bottom: 참조 View들의 아래쪽 edge 기준

left/right보다 start/end를 먼저 고려하면 RTL 언어 환경까지 생각하기 쉽습니다. 단, 기존 프로젝트가 left/right 중심으로 되어 있다면 코드 스타일을 무리하게 섞지 않는 편이 좋습니다.


GONE View를 Barrier에 포함할지 확인하기

ConstraintLayout Barrier GONE View 포함 여부 barrierAllowsGoneWidgets 이미지
GONE View까지 기준선 계산에 포함할지 여부는 barrierAllowsGoneWidgets로 조절할 수 있습니다.

Barrier를 쓸 때 놓치기 쉬운 부분이 GONE View입니다. AndroidX Barrier 레퍼런스는 Barrier가 GONE widget을 참조할 때의 기본 동작과 barrierAllowsGoneWidgets 옵션을 설명합니다. 화면 상태에 따라 label이 사라지는 UI라면 이 옵션을 반드시 확인해야 합니다.

<androidx.constraintlayout.widget.Barrier
    android:id="@+id/labelEndBarrier"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:barrierDirection="end"
    app:barrierAllowsGoneWidgets="false"
    app:constraint_referenced_ids="nameLabel,phoneLabel,emailLabel" />

barrierAllowsGoneWidgets="false"로 두면 GONE 상태의 View를 Barrier 위치 계산에서 제외할 수 있습니다. 반대로 GONE View의 위치까지 기준에 포함해야 하는 설계라면 기본 동작을 그대로 둘 수 있습니다. 중요한 것은 상태별 UI에서 이 동작을 모르고 넘어가지 않는 것입니다.


Guideline과 Barrier를 어떻게 구분할까

ConstraintLayout Guideline과 Barrier 선택 기준 비교 이미지
Guideline은 화면 기준, Barrier는 내용 기준으로 읽으면 선택이 쉬워집니다.
  • 화면 기준이면 Guideline을 먼저 생각합니다.
  • 내용 기준이면 Barrier를 먼저 생각합니다.
  • 비율 분할, 공통 여백, 고정 시작선은 Guideline이 자연스럽습니다.
  • 가변 텍스트, 다국어 문자열, 여러 label 중 가장 긴 항목 기준은 Barrier가 자연스럽습니다.
  • Guideline과 Barrier는 우열 관계가 아니라 기준이 다른 도구입니다.

12편 Guideline을 이미 읽었다면 이 차이가 더 선명해집니다. Guideline은 설계자가 정한 기준선이고, Barrier는 실제 콘텐츠가 만든 기준선입니다.


이미지 사실성 검증

ConstraintLayout Barrier 이미지 사실성 검증 카드
본문 이미지는 공식 문서에서 확인한 Barrier의 동작 범위 안에서만 표현했습니다.

이번 글의 이미지는 실제 Android Studio Preview 캡처가 아니라 설명형 도식입니다. 그래서 이미지가 공식 동작보다 과장되거나 다른 의미로 보이지 않도록 각 이미지의 핵심 주장을 factpack과 대조했습니다.

  • 짧은/긴 텍스트 이미지: Barrier가 참조 View 위치에 따라 이동한다는 공식 설명과 일치합니다.
  • Guideline 실패 이미지: Guideline은 스스로 위치를 정한다는 설명 범위 안에서 표현했습니다.
  • 가장 긴 View 기준 이미지: 지정 방향의 가장 극단 View를 기준으로 한다는 Barrier 레퍼런스와 일치합니다.
  • barrierDirection 이미지: START, END, TOP, BOTTOM 방향 상수와 일치합니다.
  • GONE 옵션 이미지: barrierAllowsGoneWidgets 설명과 일치합니다.

자주 하는 실수

  • Barrier를 실제 화면에 보이는 선이라고 생각한다.
  • 한 View만 기준이면 충분한데 불필요하게 Barrier를 만든다.
  • 참조할 View id를 constraint_referenced_ids에 빠뜨린다.
  • label은 길어지는데 value 위치를 고정 Guideline에만 붙인다.
  • GONE View가 Barrier 계산에 들어가는지 확인하지 않는다.
  • start/end와 left/right를 프로젝트 안에서 무작위로 섞는다.

한 번에 정리

  • ConstraintLayout Barrier는 동적 기준선이다.
  • 참조 View 목록은 constraint_referenced_ids로 지정한다.
  • 기준 방향은 barrierDirection으로 정한다.
  • 텍스트 길이와 다국어 문자열 때문에 기준선이 움직여야 할 때 유용하다.
  • Guideline은 화면 기준, Barrier는 내용 기준으로 구분하면 쉽다.

내용 길이가 기준선을 바꿔야 한다면 ConstraintLayout Barrier를 먼저 검토하세요. 화면 비율이나 고정 여백 기준이라면 Guideline이 더 단순합니다.


마무리

Barrier는 ConstraintLayout에서 가변 콘텐츠를 다룰 때 특히 빛을 발합니다. 텍스트 길이, 다국어 문자열, 여러 label 중 가장 긴 항목처럼 레이아웃 기준이 실행 시점에 달라질 수 있다면 Barrier가 XML을 더 안정적으로 만들어 줍니다.

공식 기준은 Android Developers ConstraintLayout 가이드AndroidX ConstraintLayout Barrier 레퍼런스를 확인했습니다. 다음 14편에서는 Group과 Placeholder를 통해 여러 View를 한 번에 숨기거나 위치를 바꾸는 방법을 이어서 보겠습니다.

Android ConstraintLayout 완전 정리 이전 글 모음

Android ConstraintLayout 완전 정리 (1) – ConstraintLayout 기본 사용법: LinearLayout과 다른 제약 기반 배치 이해하기

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

Android ConstraintLayout 완전 정리 (3) – ConstraintLayout goneMargin과 margin 차이: View.GONE일 때 간격이 바뀌는 이유

Android ConstraintLayout 완전 정리 (4) – ConstraintLayout width height 정리: wrap_content, 0dp, match_constraint 차이

Android ConstraintLayout 완전 정리 (5) – ConstraintLayout match_constraint 완전 정리: 0dp가 남은 공간을 채우는 원리

Android ConstraintLayout 완전 정리 (6) – ConstraintLayout bias 사용법: horizontalBias와 verticalBias로 위치 조절하기

Android ConstraintLayout 완전 정리 (7) – ConstraintLayout baseline 정렬: TextView 글자 기준선을 맞추는 방법

Android ConstraintLayout 완전 정리 (8) – ConstraintLayout dimensionRatio 사용법: 1:1, 16:9 이미지 비율 맞추기

Android ConstraintLayout 완전 정리 (9) – ConstraintLayout percent min max 크기 정리: 화면 크기에 맞게 View 조절하기

Android ConstraintLayout 완전 정리 (10) – ConstraintLayout chain 사용법: spread, spread_inside, packed 차이

Android ConstraintLayout 완전 정리 (11) – ConstraintLayout chain weight와 bias: 같은 폭, 다른 비율 배치 만들기

Android ConstraintLayout 완전 정리 (12) – ConstraintLayout Guideline 사용법: percent 기준선으로 화면 나누기

함께보면 좋은 글