ConstraintLayout으로 반응형 UI 빌드 Android Jetpack의 구성요소
ConstraintLayout
를 사용하면 중첩된 뷰 그룹이 없는 플랫 뷰 계층 구조로 크고 복잡한 레이아웃을 만들 수 있습니다. 이 클래스는 모든 뷰가 동위 뷰와 상위 레이아웃 간의 관계에 따라 배치된다는 점에서 RelativeLayout
와 비슷하지만 RelativeLayout
보다 유연하고 Android 스튜디오의 Layout Editor와 함께 사용하기가 더 쉽습니다.
Layout API와 Layout Editor가 서로를 위해 특별히 빌드되었기 때문에 Layout Editor의 시각적 도구에서 직접 ConstraintLayout
의 모든 기능을 사용할 수 있습니다. XML을 수정하는 대신 드래그하여 완전히 ConstraintLayout
로 레이아웃을 빌드할 수 있습니다.
이 페이지에서는 Android 스튜디오 3.0 이상에서 ConstraintLayout
를 사용하여 레이아웃을 빌드하는 방법을 보여줍니다. Layout Editor에 관한 자세한 내용은 Layout Editor로 UI 빌드를 참고하세요.
ConstraintLayout
로 만들 수 있는 다양한 레이아웃을 보려면 GitHub의 제약조건 레이아웃 예시 프로젝트를 참고하세요.
제약조건 개요
ConstraintLayout
에서 뷰의 위치를 정의하려면 뷰에 가로 및 세로 제약 조건을 각각 하나 이상 추가합니다. 각 제약 조건은 다른 뷰, 상위 요소 레이아웃 또는 표시되지 않는 가이드라인과의 연결 또는 정렬을 나타냅니다. 각 제약 조건은 세로 또는 가로축을 따라 뷰의 위치를 정의합니다. 각 뷰에는 각 축에 최소 하나의 제약조건이 있어야 하지만 더 많은 제약조건이 필요한 경우가 많습니다.
뷰를 Layout Editor에 드롭하면 제약 조건이 없더라도 그대로 둡니다. 이렇게 하면 편집을 더 쉽게 할 수 있습니다. 기기에서 레이아웃을 실행할 때 뷰에 제약 조건이 없으면 뷰가 왼쪽 상단 [0,0]에 그려집니다.
그림 1에서는 편집기에서 레이아웃이 정상적으로 표시되지만 뷰 C에는 세로 제약 조건이 없습니다. 이 레이아웃을 기기에 그릴 때 뷰 C는 뷰 A의 왼쪽과 오른쪽 가장자리에 가로로 정렬되지만 세로 제약 조건이 없으므로 화면 상단에 표시됩니다.
제약 조건 누락으로 컴파일 오류가 발생하지는 않지만 Layout Editor에서는 누락된 제약 조건을 툴바에 오류로 표시합니다. 오류 및 기타 경고를 보려면 Show Warnings and errors 를 클릭합니다. 제약 조건이 누락되지 않도록 Layout Editor에서는 자동 연결 및 제약 조건 추론 기능을 사용하여 제약 조건을 자동으로 추가합니다.
ConstraintLayout을 프로젝트에 추가
프로젝트에서 ConstraintLayout
를 사용하려면 다음 단계를 진행하세요.
settings.gradle
파일에 선언된maven.google.com
저장소가 있는지 확인합니다.Groovy
dependencyResolutionManagement { ... repositories { google() } )
Kotlin
dependencyResolutionManagement { ... repositories { google() } }
- 다음 예와 같이 모듈을 모듈 수준
build.gradle
파일에 종속 항목으로 추가합니다. 최신 버전은 다음 예에 표시된 것과 다를 수 있습니다.Groovy
dependencies { implementation "androidx.constraintlayout:constraintlayout:2.2.0-alpha13" // To use constraintlayout in compose implementation "androidx.constraintlayout:constraintlayout-compose:1.1.0-alpha13" }
Kotlin
dependencies { implementation("androidx.constraintlayout:constraintlayout:2.2.0-alpha13") // To use constraintlayout in compose implementation("androidx.constraintlayout:constraintlayout-compose:1.1.0-alpha13") }
- 툴바 또는 동기화 알림에서 Sync Project with Gradle Files를 클릭합니다.
이제 ConstraintLayout
으로 레이아웃을 빌드할 준비가 되었습니다.
레이아웃 변환
기존 레이아웃을 제약조건 레이아웃으로 변환하려면 다음 단계를 따르세요.
- Android 스튜디오에서 레이아웃을 열고 편집기 창 하단에 있는 Design 탭을 클릭합니다.
- Component Tree 창에서 레이아웃을 마우스 오른쪽 버튼으로 클릭하고 Convert LinearLayout to ConstraintLayout을 클릭합니다.
새 레이아웃 생성
새 제약조건 레이아웃 파일을 시작하려면 다음 단계를 따르세요.
- Project 창에서 모듈 폴더를 클릭하고 File > New > XML > Layout XML을 선택합니다.
- 레이아웃 파일의 이름을 입력하고 Root Tag에 'androidx.constraintlayout.widget.ConstraintLayout'을 입력합니다.
- Finish를 클릭합니다.
제약조건 추가 또는 삭제
제약조건을 추가하려면 다음 단계를 따르세요.
Palette 창에서 편집기로 보기를 드래그합니다.
ConstraintLayout
에 뷰를 추가하면 각 모서리에 정사각형 크기 조절 핸들과 각 측면에 원형 제약 조건 핸들이 있는 경계 상자에 표시됩니다.- 보기를 클릭하여 선택합니다.
- 다음 중 한 가지 방법을 사용합니다.
- 제약조건 핸들을 클릭하여 사용 가능한 앵커 포인트로 드래그합니다. 이 지점은 다른 보기의 가장자리, 레이아웃의 가장자리 또는 안내선일 수 있습니다. 제약 조건 핸들을 드래그하면 Layout Editor에 잠재적 연결 앵커와 파란색 오버레이가 표시됩니다.
그림 4와 같이 Attributes 창의 Layout 섹션에서 Create a connection 버튼 중 하나를 클릭합니다.
제약 조건이 생성되면 편집기에서 기본 여백을 부여하여 두 뷰를 구분합니다.
제약조건을 만들 때 다음 규칙을 기억하세요.
- 모든 뷰에는 가로와 세로 하나라는 두 개 이상의 제약 조건이 있어야 합니다.
- 동일한 평면을 공유하는 제약 조건 핸들과 앵커 포인트 간에만 제약 조건을 만들 수 있습니다. 보기의 세로 평면(왼쪽 및 오른쪽)은 다른 세로 평면으로만 제한될 수 있으며 기준은 다른 기준으로만 제한될 수 있습니다.
- 각 제약조건 핸들은 하나의 제약조건에만 사용할 수 있지만 여러 뷰에서 동일한 앵커 포인트에 여러 제약 조건을 만들 수 있습니다.
다음 중 하나를 실행하여 제약조건을 삭제할 수 있습니다.
- 제약조건을 클릭하여 선택한 다음 삭제를 클릭합니다.
제약 조건 앵커를 Control 키를 누른 상태에서 클릭합니다 (macOS의 경우 Command 키를 누른 상태에서 클릭). 그림 5와 같이 제약조건이 빨간색으로 바뀌어 클릭하여 삭제할 수 있음을 나타냅니다.
Attributes 창의 Layout 섹션에서 그림 6과 같이 제약 조건 앵커를 클릭합니다.
뷰에 반대되는 제약 조건을 추가하면 제약 조건 선이 스프링처럼 감겨 있어 동영상 2와 같이 반대 힘을 나타냅니다. 이 효과는 뷰 크기가 '고정' 또는 '콘텐츠 래핑'으로 설정될 때 가장 잘 나타납니다. 이 경우 뷰는 제약 조건 사이의 중앙에 배치됩니다. 대신 제약 조건에 맞게 뷰 크기를 늘리려면 '제약조건과 일치'하도록 크기를 전환합니다. 현재 크기를 유지하되 뷰가 중앙에 오지 않도록 이동하려면 제약조건 편향을 조정하세요.
다음 섹션에 설명된 대로 제약조건을 사용하여 다양한 유형의 레이아웃 동작을 실행할 수 있습니다.
상위 요소 포지셔닝
뷰의 측면을 레이아웃의 상응하는 가장자리로 제한합니다.
그림 7에서 뷰의 왼쪽은 상위 요소 레이아웃의 왼쪽 가장자리에 연결됩니다. 여백을 사용하여 가장자리로부터의 거리를 정의할 수 있습니다.
위치 순서 지정
두 뷰의 표시 순서를 세로 또는 가로로 정의합니다.
그림 8에서 B는 항상 A의 오른쪽에 있도록 제한되고 C는 A 아래 있도록 제한됩니다. 그러나 이러한 제약 조건은 정렬을 의미하지 않으므로 B는 계속 위아래로 이동할 수 있습니다.
정렬
보기의 가장자리를 다른 보기의 가장자리에 맞게 정렬합니다.
그림 9에서 B의 왼쪽은 A의 왼쪽에 맞게 정렬됩니다. 뷰 중심을 정렬하려면 양쪽에 제약 조건을 만듭니다.
제약 조건에서 안쪽으로 뷰를 드래그하여 정렬을 오프셋할 수 있습니다. 예를 들어 그림 10에서는 24dp 오프셋 정렬을 사용하는 B를 보여줍니다. 오프셋은 제한된 뷰의 여백으로 정의됩니다.
정렬할 뷰를 모두 선택한 다음 툴바에서 Align 을 클릭하여 정렬 유형을 선택할 수도 있습니다.
기준선 정렬
보기의 텍스트 기준선을 다른 보기의 텍스트 기준선에 맞춥니다.
그림 11에서 B의 첫 번째 줄은 A의 텍스트에 맞게 정렬됩니다.
기준선 제약조건을 만들려면 제한할 텍스트 뷰를 마우스 오른쪽 버튼으로 클릭한 다음 Show Baseline을 클릭합니다. 그런 다음 텍스트 기준선을 클릭하고 선을 다른 기준선으로 드래그합니다.
안내선으로 제한
뷰를 제한하고 앱 사용자에게는 표시되지 않도록 세로 또는 가로 가이드라인을 추가할 수 있습니다. dp 단위 또는 레이아웃 가장자리를 기준으로 한 백분율에 따라 레이아웃 내에 가이드라인을 배치할 수 있습니다.
안내선을 만들려면 툴바에서 Guidelines 를 클릭한 다음 Add Vertical Guideline 또는 Add Horizontal Guideline을 클릭합니다.
점선을 드래그하여 위치를 조정하고 안내선 가장자리의 원을 클릭하여 측정 모드를 전환합니다.
경계선으로 제한
안내선과 마찬가지로 경계선은 뷰를 제한할 수 있는 보이지 않는 선입니다. 단, 경계선이 자체 위치를 정의하지는 않습니다. 대신 경계선 위치는 포함된 뷰의 위치에 따라 이동합니다. 이 방법은 하나의 특정 뷰가 아닌 일련의 뷰로 뷰를 제한하려는 경우에 유용합니다.
예를 들어, 그림 13에서 뷰 C는 경계선의 오른쪽으로 제한됩니다. 경계선은 보기 A와 보기 B의 '끝' (또는 왼쪽에서 오른쪽 레이아웃에서는 오른쪽)으로 설정됩니다. 경계선은 뷰 A의 오른쪽 또는 뷰 B의 오른쪽 중 맨 오른쪽에 있는지에 따라 이동합니다.
경계선을 만들려면 다음 단계를 따르세요.
- 툴바에서 Guidelines 를 클릭한 후 Add Vertical Barrier 또는 Add Horizontal Barrier를 클릭합니다.
- Component Tree 창에서 경계선 내부의 원하는 보기를 선택하여 경계선 구성요소로 드래그합니다.
- Component Tree에서 경계선을 선택하고 Attributes 창을 연 다음 barrierDirection을 설정합니다.
이제 다른 보기에서 경계선으로의 제약조건을 만들 수 있습니다.
경계선 내부의 뷰를 경계선으로 제한할 수도 있습니다. 이렇게 하면 어느 뷰가 가장 길거나 가장 높은지 모르더라도 경계선에 있는 모든 뷰를 서로 정렬할 수 있습니다.
경계선의 '최소' 위치를 보장하기 위해 경계선 내부에 안내선을 포함할 수도 있습니다.
제약조건 편향 조정
뷰의 양쪽에 제약 조건을 추가하고 동일한 크기의 뷰 크기가 '고정' 또는 '콘텐츠 래핑'이면 뷰가 두 제약 조건 사이의 중앙에 배치되며 기본적으로 편향은 50% 입니다. 동영상 3과 같이 Attributes 창에서 편향 슬라이더를 드래그하거나 뷰를 드래그하여 편향을 조정할 수 있습니다.
대신 제약 조건에 맞게 보기의 크기를 늘리려면 '제약조건과 일치'하도록 크기를 전환합니다.
보기 크기 조정
모서리 핸들을 사용하여 뷰 크기를 조절할 수 있지만 그러면 크기가 하드코딩됩니다. 즉, 뷰는 다른 콘텐츠나 화면 크기에 맞게 크기가 조절되지 않습니다. 다른 크기 조정 모드를 선택하려면 뷰를 클릭하고 편집기의 오른쪽에 있는 Attributes 창을 엽니다.
Attributes 창 상단에는 뷰 검사기가 있습니다. 여기에는 그림 14와 같이 여러 레이아웃 속성의 컨트롤이 포함되어 있습니다. 이 기능은 제약 조건 레이아웃의 뷰에만 사용할 수 있습니다.
그림 14에서 설명선 3으로 표시된 기호를 클릭하여 높이와 너비를 계산하는 방법을 변경할 수 있습니다. 이러한 기호는 다음과 같이 크기 모드를 나타냅니다. 기호를 클릭하여 다음 설정 간에 전환합니다.
- 고정: 다음 텍스트 상자에서 특정 크기를 지정하거나 편집기에서 뷰 크기를 조절합니다.
- 콘텐츠 래핑: 보기가 콘텐츠에 맞게 필요한 만큼만 확장됩니다.
- layout_constraintWidth
-
Match Constraints: 뷰의 여백을 고려한 후 뷰가 양쪽의 제약 조건에 맞게 최대한 크게 확장됩니다. 그러나 다음 속성과 값을 사용하여 동작을 수정할 수 있습니다. 다음 속성은 보기 너비를 '제약조건과 일치'로 설정한 경우에만 적용됩니다.
- layout_constraintWidth_min
보기의 최소 너비에
dp
측정기준을 사용합니다. - layout_constraintWidth_max
보기의 최대 너비에
dp
측정기준을 사용합니다.
그러나 지정된 측정기준에 제약 조건이 하나만 있으면 보기가 콘텐츠에 맞게 확장됩니다. 높이 또는 너비로 이 모드를 사용하면 크기 비율을 설정할 수도 있습니다.
- layout_constraintWidth_min
가로 크기가 제약 조건을 따르도록 변경하려면 true
로 설정합니다. 기본적으로 WRAP_CONTENT
로 설정된 위젯은 제약 조건으로 제한되지 않습니다.
크기를 비율로 설정
하나 이상의 뷰 크기가 '제약조건과 일치' (0dp
)로 설정된 경우 뷰 크기를 16:9와 같은 비율로 설정할 수 있습니다. 비율을 사용 설정하려면 가로세로 비율 제약 조건 전환 (그림 14의 1 참조)을 클릭하고 표시되는 입력에 width:height 비율을 입력합니다.
너비와 높이가 모두 '제약조건과 일치'로 설정된 경우 Toggle Aspect Ratio Constraint를 클릭하여 다른 측정기준의 비율을 기반으로 할 측정기준을 선택할 수 있습니다. 뷰 검사기에서는 상응하는 가장자리를 실선으로 연결하여 비율로 설정할 측정기준을 나타냅니다.
예를 들어 양쪽을 '제약조건과 일치'로 설정했다면 Toggle Aspect Ratio Constraint를 두 번 클릭하여 너비가 높이의 비율이 되도록 설정합니다. 전체 크기는 뷰의 높이로 결정되며 이는 그림 15와 같이 어떤 방식으로든 정의할 수 있습니다.
보기 여백 조정
뷰를 균일한 간격으로 만들려면 툴바에서 Margin 을 클릭하여 레이아웃에 추가하는 각 뷰의 기본 여백을 선택합니다. 기본 여백을 변경하면 이후에 추가하는 보기에만 적용됩니다.
각 제약조건을 나타내는 줄의 숫자를 클릭하여 Attributes 창에서 각 뷰의 여백을 제어할 수 있습니다. 그림 14에서 콜아웃 4는 하단 여백이 16dp로 설정되어 있음을 보여줍니다.
도구에서 제공하는 모든 여백은 뷰가 Material Design의 8dp 정사각형 그리드 권장사항에 맞게 정렬되는 데 도움이 되는 8dp의 인수입니다.
체인이 있는 선형 그룹 제어
체인은 양방향 위치 제약 조건으로 서로 연결된 뷰 그룹입니다. 체인 내의 보기는 세로 또는 가로로 분산될 수 있습니다.
체인 스타일은 다음 방법 중 하나로 지정할 수 있습니다.
- 넓히기: 여백을 고려한 후 뷰가 균등하게 분산됩니다. 이는 기본값입니다.
- 내부로 확산: 첫 번째 보기와 마지막 보기가 체인의 각 끝에 있는 제약조건에 고정되고 나머지 보기는 균등하게 분산됩니다.
- 가중치 적용: 체인이 펼치기 또는 내부에서 넓히기로 설정된 경우 하나 이상의 보기를 '제약조건과 일치' (
0dp
)하도록 설정하여 남은 공간을 채울 수 있습니다. 기본적으로 '제약조건과 일치'로 설정된 각 보기 간에 공간은 균일하게 분산되지만layout_constraintHorizontal_weight
및layout_constraintVertical_weight
속성을 사용하여 각 보기에 중요도 가중치를 할당할 수 있습니다. 이는 선형 레이아웃의layout_weight
와 같은 방식으로 작동합니다. 가중치 값이 가장 높은 뷰에 가장 많은 공간이 할당되고 가중치가 동일한 뷰에는 동일한 크기의 공간이 부여됩니다. - 패킹됨: 여백을 고려한 후 뷰가 함께 패킹됩니다. 체인의 '헤드' 뷰 바이어스를 변경하여 체인의 전체 편향(왼쪽 또는 오른쪽 또는 위쪽 또는 아래쪽)을 조정할 수 있습니다.
체인의 '헤드' 뷰(가로 체인의 가장 왼쪽 뷰(왼쪽에서 오른쪽 레이아웃))와 세로 체인의 맨 위에 있는 뷰는 XML에서 체인의 스타일을 정의합니다. 그러나 체인의 뷰를 선택하고 뷰 아래에 표시되는 체인 버튼 을 클릭하여 넓히기, 내부에서 넓히기, 채워짐 간에 전환할 수 있습니다.
체인을 만들려면 동영상 4와 같이 다음 단계를 따르세요.
- 체인에 포함할 보기를 모두 선택합니다.
- 뷰 중 하나를 마우스 오른쪽 버튼으로 클릭합니다.
- 체인점을 선택합니다.
- 가로 가운데 중심 또는 세로 중심을 선택합니다.
다음은 체인을 사용할 때 고려할 몇 가지 사항입니다.
- 뷰는 가로 및 세로 체인의 일부가 될 수 있으므로 유연한 그리드 레이아웃을 빌드할 수 있습니다.
- 그림 14와 같이 체인의 각 끝이 같은 축의 다른 객체로 제한된 경우에만 체인이 올바르게 작동합니다.
- 체인의 방향이 세로 또는 가로이지만 체인을 사용하면 보기가 해당 방향으로 정렬되지 않습니다. 체인에서 각 뷰의 적절한 위치를 확보하려면 정렬 제약 조건과 같은 다른 제약 조건을 포함합니다.
자동으로 제약조건 만들기
레이아웃에 배치할 때 모든 뷰에 제약 조건을 추가하는 대신 Layout Editor에서 원하는 위치로 각 뷰를 이동한 다음 Infer Constraints 를 클릭하여 제약 조건을 자동으로 생성할 수 있습니다.
Infer Constraints에서는 레이아웃을 스캔하여 모든 뷰에 가장 효과적인 제약 조건 집합을 결정합니다. 뷰를 현재 위치로 제한하면서 유연성을 제공합니다. 다양한 화면 크기와 방향에 맞게 레이아웃이 반응하도록 조정해야 할 수 있습니다.
부모에 자동 연결은 사용 설정할 수 있는 별도의 기능입니다. 이 기능을 사용 설정한 상태에서 상위 뷰에 하위 뷰를 추가하면 뷰를 상위 레이아웃으로 제한하는 것이 적절한 경우에만 레이아웃에 뷰를 추가할 때 이 기능을 통해 각 뷰에 관한 제약 조건이 두 개 이상 자동으로 생성됩니다. 자동 연결은 레이아웃의 다른 뷰에 관한 제약 조건을 생성하지 않습니다.
자동 연결은 기본적으로 사용되지 않습니다. Layout Editor 툴바에서 Enable Autoconnection to Parent 를 클릭하여 사용 설정합니다.
키프레임 애니메이션
ConstraintLayout
내에서 ConstraintSet
및 TransitionManager
를 사용하여 요소의 크기와 위치 변경사항을 애니메이션으로 보여줄 수 있습니다.
ConstraintSet
는 ConstraintLayout
내에 있는 모든 하위 요소의 제약 조건, 여백, 패딩을 나타내는 경량 객체입니다. 표시된 ConstraintLayout
에 ConstraintSet
를 적용하면 레이아웃은 모든 하위 요소의 제약 조건을 업데이트합니다.
ConstraintSet
를 사용하여 애니메이션을 빌드하려면 애니메이션의 시작 및 종료 키프레임 역할을 하는 두 개의 레이아웃 파일을 지정합니다. 그런 다음 두 번째 키프레임 파일에서 ConstraintSet
를 로드하여 표시된 ConstraintLayout
에 적용할 수 있습니다.
다음 코드 예에서는 단일 버튼을 화면 하단으로 이동하는 애니메이션을 보여주는 방법을 보여줍니다.
// MainActivity.kt
fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.keyframe_one)
constraintLayout = findViewById(R.id.constraint_layout) // member variable
}
fun animateToKeyframeTwo() {
val constraintSet = ConstraintSet()
constraintSet.load(this, R.layout.keyframe_two)
TransitionManager.beginDelayedTransition()
constraintSet.applyTo(constraintLayout)
}
// layout/keyframe1.xml // Keyframe 1 contains the starting position for all elements in the animation // as well as final colors and text sizes. <?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/button2" android:layout_width="0dp" android:layout_height="wrap_content" android:text="Button" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
// layout/keyframe2.xml // Keyframe 2 contains another ConstraintLayout with the final positions. <?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/button2" android:layout_width="0dp" android:layout_height="wrap_content" android:text="Button" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintBottom_toBottomOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
추가 리소스
ConstraintLayout
는 Sunflower 데모 앱에서 사용됩니다.