|

Android ConstraintLayout 완전 정리 (14) – ConstraintLayout Group과 Placeholder: 여러 View 숨기기와 위치 바꾸기

Android ConstraintLayout 완전 정리 (14) – ConstraintLayout Group과 Placeholder: 여러 View 숨기기와 위치 바꾸기
ConstraintLayout Group과 Placeholder는 helper지만 해결하는 문제가 서로 다릅니다.

ConstraintLayout Group은 여러 View의 표시 상태를 한 번에 바꾸고 싶을 때 쓰는 helper입니다. 반면 Placeholder는 특정 View를 지정한 슬롯 위치에 보여주고 싶을 때 쓰는 helper에 가깝습니다.

둘 다 ConstraintLayout 안에서 View처럼 선언되기 때문에 처음에는 비슷해 보입니다. 하지만 Group은 여러 View를 묶어 visibility를 제어하는 문제에 가깝고, Placeholder는 contentId로 한 View의 위치를 바꾸는 문제에 가깝습니다.


ConstraintLayout Group 핵심 정리

  • Group은 여러 View의 visibility를 함께 바꾸는 helper입니다.
  • 참조할 View는 app:constraint_referenced_ids에 적습니다.
  • Group은 LinearLayout 같은 배치 컨테이너가 아닙니다.
  • 각 View의 실제 위치는 각자의 constraint가 결정합니다.
  • 로딩 영역, 로그인 전후 버튼 묶음처럼 상태가 함께 바뀌는 UI에 잘 맞습니다.
ConstraintLayout Group으로 여러 View visibility를 함께 바꾸는 이미지
Group은 여러 View를 하나의 helper로 묶어 visibility를 함께 바꿀 수 있습니다.

Group은 배치 컨테이너가 아니다

ConstraintLayout Group은 배치 컨테이너가 아니라 visibility helper라는 설명 이미지
Group은 LinearLayout 같은 컨테이너가 아니라 참조 View에 속성을 적용하는 helper입니다.

Group에서 가장 많이 하는 실수는 Group을 ViewGroup처럼 생각하는 것입니다. Group은 참조 View를 담는 박스가 아닙니다. Group 자체에 start, top 제약을 걸었다고 해서 참조 View들이 그 안으로 자동 배치되지 않습니다.

<androidx.constraintlayout.widget.Group
    android:id="@+id/loginGroup"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:visibility="gone"
    app:constraint_referenced_ids="titleText,messageText,actionButton" />

이 XML은 titleText, messageText, actionButton을 한 번에 숨기기 위한 구조입니다. 세 View의 위치는 여전히 각 View에 걸린 constraint가 결정합니다.


로딩 영역 여러 View 숨기기

ConstraintLayout Group으로 로딩 영역 여러 View를 함께 숨기는 예시
로딩 UI처럼 여러 View가 같은 상태로 움직일 때 Group이 유용합니다.

로딩 화면에서는 ProgressBar, 안내 문구, 취소 버튼이 함께 보이거나 함께 사라지는 경우가 많습니다. 이럴 때 각 View의 visibility를 코드에서 하나씩 바꾸면 상태가 늘어날수록 실수가 생깁니다.

<ProgressBar
    android:id="@+id/progress"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

<TextView
    android:id="@+id/loadingMessage"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="불러오는 중입니다" />

<Button
    android:id="@+id/cancelButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="취소" />

<androidx.constraintlayout.widget.Group
    android:id="@+id/loadingGroup"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:constraint_referenced_ids="progress,loadingMessage,cancelButton" />

이제 화면 상태가 바뀔 때 loadingGroup.visibility = View.GONE처럼 묶어서 처리할 수 있습니다. XML에서는 helper를 사용하고, 실제 상태 변경은 코드나 데이터 바인딩에서 제어하는 흐름으로 보면 됩니다.


Placeholder는 content를 특정 자리로 옮겨 보여준다

ConstraintLayout Placeholder로 content View를 강조 위치에 배치하는 이미지
Placeholder는 지정한 content View를 Placeholder 자리로 보여주는 데 사용할 수 있습니다.

Placeholder는 Group과 목적이 다릅니다. 여러 View를 함께 숨기는 것이 아니라, 지정한 content View를 Placeholder가 있는 자리에서 보여주는 방식입니다. 강조 카드, 선택된 아이템 미리보기, 상태별 대표 콘텐츠 슬롯처럼 한 View를 다른 위치에 보여주고 싶을 때 생각해 볼 수 있습니다.

<androidx.constraintlayout.widget.Placeholder
    android:id="@+id/highlightSlot"
    android:layout_width="0dp"
    android:layout_height="96dp"
    app:content="@id/promoCard"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent" />

<TextView
    android:id="@+id/promoCard"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:text="오늘의 추천" />

AndroidX Placeholder 레퍼런스는 content view id를 설정하는 setContentId와 content가 없을 때의 동작을 다루는 setEmptyVisibility를 제공합니다. XML에서는 프로젝트 설정과 ConstraintLayout 버전에 맞춰 속성 지원을 확인하는 편이 좋습니다.


Placeholder가 비어 있을 때도 설계가 필요하다

ConstraintLayout Placeholder emptyVisibility가 주변 View 배치에 미치는 영향 이미지
Placeholder가 비어 있을 때 보이지 않는 공간을 남길지, 사라질지 판단해야 합니다.

Placeholder는 content가 있을 때만 생각하면 안 됩니다. content가 아직 없거나 상태상 비어 있을 때 그 자리가 공간을 차지해야 하는지, 완전히 사라져야 하는지에 따라 주변 View 배치가 달라질 수 있습니다.

  • INVISIBLE처럼 공간을 남기는 방식은 아래 View의 위치를 안정적으로 유지할 수 있습니다.
  • GONE처럼 사라지는 방식은 빈 슬롯 때문에 화면이 어색하게 비는 문제를 줄일 수 있습니다.
  • 주변 View가 Placeholder의 bottom이나 top에 제약되어 있다면 empty visibility 차이가 더 중요해집니다.

Group과 Placeholder 차이

ConstraintLayout Group과 Placeholder 역할 차이 비교 이미지
Group은 상태 제어, Placeholder는 content 위치 대체라는 관점으로 구분하면 쉽습니다.
  • Group: 여러 View를 함께 보이거나 숨기는 helper입니다.
  • Placeholder: 특정 content View를 지정한 슬롯에 보여주는 helper입니다.
  • Group은 참조 View의 위치를 새로 계산해 주는 컨테이너가 아닙니다.
  • Placeholder는 content가 없을 때의 visibility까지 함께 판단해야 합니다.
  • 여러 View의 상태 제어라면 Group, 한 content의 위치 대체라면 Placeholder를 먼저 검토합니다.

로그인 전후 버튼 묶음 예시

ConstraintLayout Group으로 로그인 전후 버튼 묶음을 제어하는 예시
상태별 버튼 묶음은 Group으로 visibility를 분리하면 읽기 쉽습니다.

로그인 전에는 로그인/가입 버튼을 보여주고, 로그인 후에는 프로필/로그아웃 버튼을 보여주는 화면을 생각해 보겠습니다. 이런 화면에서는 각 버튼의 위치보다 어떤 버튼 묶음이 현재 상태에 맞는지가 더 중요합니다.

<androidx.constraintlayout.widget.Group
    android:id="@+id/guestActionsGroup"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:constraint_referenced_ids="loginButton,joinButton" />

<androidx.constraintlayout.widget.Group
    android:id="@+id/memberActionsGroup"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:constraint_referenced_ids="profileButton,logoutButton" />

코드에서는 로그인 상태에 따라 guest group과 member group의 visibility를 반대로 바꾸면 됩니다. 이때 버튼들의 배치는 여전히 각 버튼의 constraint가 담당합니다.


자주 하는 실수

  • Group을 ViewGroup처럼 생각하고 자식 배치를 기대한다.
  • Group에 constraint를 걸면 참조 View도 같이 이동한다고 생각한다.
  • Group으로 숨긴 View의 constraint 관계가 주변 View에 미치는 영향을 확인하지 않는다.
  • Placeholder가 비어 있을 때 visibility 동작을 확인하지 않는다.
  • 상태 전환이 많아졌는데 모든 View visibility를 개별 코드로만 관리한다.

한 번에 정리

  • ConstraintLayout Group은 여러 View의 visibility를 함께 제어하는 helper다.
  • Group은 배치 컨테이너가 아니며 위치는 각 View의 constraint가 정한다.
  • ConstraintLayout Placeholder는 content View를 특정 슬롯 위치에 보여주는 helper다.
  • Placeholder는 content가 없을 때의 visibility까지 설계해야 한다.
  • 상태 묶음은 Group, content 위치 대체는 Placeholder로 먼저 나눠서 생각한다.

여러 View를 함께 숨기는 문제라면 Group, 한 View를 다른 자리에서 보여주는 문제라면 Placeholder를 먼저 검토하세요.


마무리

Group과 Placeholder는 ConstraintLayout에서 helper라는 공통점이 있지만 해결하는 문제가 다릅니다. Group은 여러 View의 상태를 묶어 관리하는 도구이고, Placeholder는 content를 특정 위치에 배치하는 슬롯에 가깝습니다.

공식 기준은 AndroidX Group 레퍼런스AndroidX Placeholder 레퍼런스를 확인했습니다. 다음 15편에서는 Flow helper로 chip과 tag UI를 자동 줄바꿈 배치하는 방법을 이어서 보겠습니다.

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 기준선으로 화면 나누기

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

함께보면 좋은 글