ConstraintLayout으로 반응형 UI 빌드 Android Jetpack의 구성요소
ConstraintLayout
를 사용하면 중첩된 뷰 그룹이 없는 플랫 뷰 계층 구조를 사용하여 크고 복잡한 레이아웃을 만들 수 있습니다. 동위 뷰와 상위 레이아웃 간의 관계에 따라 모든 뷰가 배치된다는 점에서 RelativeLayout
와 비슷하지만 RelativeLayout
보다 유연하고 Android 스튜디오의 Layout Editor와 함께 사용하기가 더 쉽습니다.
레이아웃 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-beta01" // To use constraintlayout in compose implementation "androidx.constraintlayout:constraintlayout-compose:1.1.0-beta01" }
Kotlin
dependencies { implementation("androidx.constraintlayout:constraintlayout:2.2.0-beta01") // To use constraintlayout in compose implementation("androidx.constraintlayout:constraintlayout-compose:1.1.0-beta01") }
- 툴바 또는 동기화 알림에서 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_constrainedWidth
-
제약조건과 일치: 보기가 양쪽의 제약조건에 맞게 최대한 많이 확장됩니다(보기의 여백을 고려한 후). 그러나 다음 속성과 값을 사용하여 동작을 수정할 수 있습니다. 다음 속성은 보기 너비를 '제약조건과 일치'로 설정한 경우에만 적용됩니다.
- 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로 설정되었음을 보여줍니다.
이 도구에서는 모든 여백이 8dp의 배수로 표시되어 보기를 머티리얼 디자인의 8dp 정사각형 그리드 추천에 맞게 정렬하는 데 도움이 됩니다.
체인이 있는 선형 그룹 제어
체인은 양방향 위치 제약 조건을 통해 서로 연결된 보기 그룹입니다. 체인의 뷰는 세로 또는 가로로 분산될 수 있습니다.
체인 스타일은 다음 방법 중 하나로 지정할 수 있습니다.
- 넓히기: 여백을 고려한 후 보기가 균등하게 분산됩니다. 이는 기본값입니다.
- 내부에서 넓히기: 첫 번째 보기와 마지막 보기는 체인의 각 끝에 있는 제약조건에 고정되고 나머지 보기는 균등하게 분산됩니다.
- 가중치: 체인이 펼치기 또는 안쪽으로 펼치기로 설정된 경우 하나 이상의 뷰를 '제약 조건에 맞추기' (
0dp
)로 설정하여 남은 공간을 채울 수 있습니다. 기본적으로 공간은 '제약 조건에 맞추기'로 설정된 각 뷰 간에 균등하게 분산되지만layout_constraintHorizontal_weight
및layout_constraintVertical_weight
속성을 사용하여 각 뷰에 중요도 가중치를 할당할 수 있습니다. 이는 선형 레이아웃에서layout_weight
와 동일한 방식으로 작동합니다. 가중치 값이 가장 높은 뷰에 가장 많은 공간이 할당되고 가중치가 동일한 뷰에는 동일한 크기의 공간이 할당됩니다. - 패킹됨: 여백을 고려한 후 보기가 함께 배치됩니다. 체인의 '헤드' 보기 편향을 변경하여 전체 체인의 편향(좌우 또는 상하)을 조정할 수 있습니다.
체인의 '헤드' 보기(가로 체인에서는 맨 왼쪽에 있는 보기이고, 세로 체인에서는 맨 위에 있는 보기)를 통해 XML에 체인의 스타일을 정의합니다. 그러나 체인에서 보기를 선택한 다음 보기 아래에 표시되는 체인 버튼 을 클릭하여 넓히기, 내부에서 넓히기, 채우기 간에 전환할 수 있습니다.
체인을 만들려면 동영상 4와 같이 다음 단계를 따르세요.
- 체인에 포함할 뷰를 모두 선택합니다.
- 뷰 중 하나를 마우스 오른쪽 버튼으로 클릭합니다.
- 체인을 선택합니다.
- Center Horizontally 또는 Center Vertically를 선택합니다.
다음은 체인을 사용할 때 고려해야 할 사항입니다.
- 뷰는 가로 및 세로 체인의 일부가 될 수 있으므로 유연한 그리드 레이아웃을 만들 수 있습니다.
- 그림 14와 같이 체인의 각 끝이 같은 축의 다른 개체로 제한된 경우에만 체인이 제대로 작동합니다.
- 체인의 방향이 세로 또는 가로이지만 체인을 사용해도 보기가 해당 방향으로 정렬되지 않습니다. 체인에 있는 각 뷰의 적절한 위치를 얻으려면 정렬 제약조건과 같은 다른 제약조건을 포함합니다.
자동으로 제약조건 만들기
레이아웃에 배치할 때 모든 보기에 제약조건을 추가하는 대신 Layout Editor에서 각 보기를 원하는 위치로 이동한 다음 Infer Constraints 를 클릭하여 자동으로 제약조건을 만듭니다.
Infer Constraints는 레이아웃을 검사하여 모든 뷰에 가장 효과적인 제약 조건 집합을 결정합니다. 뷰를 현재 위치로 제한하면서 유연성을 제공합니다. 다른 화면 크기와 방향에도 레이아웃이 제대로 반응하도록 조정해야 할 수도 있습니다.
Autoconnect to Parent는 개별적으로 사용할 수 있는 기능입니다. 이 기능을 사용 설정하고 상위 요소에 하위 뷰를 추가하면 레이아웃에 뷰를 추가할 때 뷰마다 제약 조건이 두 개 이상 자동으로 생성됩니다. 단, 뷰를 상위 레이아웃으로 제한하는 것이 적합한 경우에만 생성됩니다. 자동 연결은 레이아웃에 있는 다른 뷰에 대한 제약 조건을 생성하지 않습니다.
자동 연결은 기본적으로 사용되지 않습니다. Layout Editor 툴바에서 Enable Autoconnection to Parent 를 클릭하여 사용 설정합니다.
키프레임 애니메이션
ConstraintLayout
내에서 ConstraintSet
및 TransitionManager
를 사용하여 요소의 크기 및 위치 변경사항을 애니메이션으로 표시할 수 있습니다.
ConstraintSet
은 ConstraintLayout
내 모든 하위 요소의 제약 조건, 여백, 패딩을 나타내는 경량 객체입니다. ConstraintSet
를 표시된 ConstraintLayout
에 적용하면 레이아웃에서 모든 하위 요소의 제약조건을 업데이트합니다.
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 데모 앱에서 사용됩니다.