ConstraintLayout으로 반응형 UI 빌드 Android Jetpack의 구성요소

Compose 방식 사용해 보기
Jetpack Compose는 Android에 권장되는 UI 도구 키트입니다. Compose에서 레이아웃을 사용하는 방법을 알아보세요.

ConstraintLayout를 사용하면 중첩된 뷰 그룹이 없는 플랫 뷰 계층 구조를 사용하여 크고 복잡한 레이아웃을 만들 수 있습니다. 동위 뷰와 상위 레이아웃 간의 관계에 따라 모든 뷰가 배치된다는 점에서 RelativeLayout와 비슷하지만 RelativeLayout보다 유연하고 Android 스튜디오의 Layout Editor와 함께 사용하기가 더 쉽습니다.

ConstraintLayout의 모든 기능은 Layout Editor의 시각적 도구에서 직접 사용할 수 있습니다. Layout API와 Layout Editor는 특별히 서로 빌드되어 있기 때문입니다. XML을 수정하는 대신 드래그만으로 ConstraintLayout로 레이아웃을 빌드할 수 있습니다.

이 페이지에서는 Android 스튜디오 3.0 이상에서 ConstraintLayout를 사용하여 레이아웃을 빌드하는 방법을 보여줍니다. Layout Editor에 관한 자세한 내용은 Layout Editor로 UI 빌드를 참고하세요.

ConstraintLayout로 만들 수 있는 다양한 레이아웃을 보려면 GitHub의 제약 조건 레이아웃 예시 프로젝트를 참고하세요.

제약조건 개요

ConstraintLayout에서 뷰의 위치를 정의하려면 뷰에 가로 제약 조건과 세로 제약 조건을 각각 하나 이상 추가합니다. 각 제약조건은 다른 뷰, 상위 레이아웃 또는 표시되지 않는 안내선과의 연결 또는 정렬을 나타냅니다. 각 제약조건은 세로축 또는 가로축을 따라 뷰의 위치를 정의합니다. 각 뷰에는 각 축에 최소 하나의 제약조건이 있어야 하지만 더 많은 제약조건이 필요한 경우가 많습니다.

뷰를 Layout Editor에 드롭하면 제약 조건이 없어도 그대로 둔 위치에 유지됩니다. 이는 편집을 더 쉽게 하기 위함일 뿐입니다. 기기에서 레이아웃을 실행할 때 뷰에 제약 조건이 없으면 [0,0] 위치(왼쪽 상단)에 그려집니다.

그림 1에서는 편집기에서 레이아웃이 제대로 보이지만, 뷰 C에 세로 제약 조건이 없습니다. 이 레이아웃이 기기에 그려질 때 뷰 C는 뷰 A의 왼쪽 및 오른쪽 가장자리와 가로로 정렬되지만 세로 제약 조건이 없으므로 화면 상단에 표시됩니다.

그림 1. 편집기는 A 아래에 뷰 C를 표시하지만 세로 제약 조건은 없습니다.

그림 2. 뷰 C는 이제 뷰 A 아래로 세로로 제한됩니다.

제약 조건이 누락되더라도 컴파일 오류가 발생하지는 않지만, Layout Editor는 누락된 제약 조건을 툴바에서 오류로 표시합니다. 오류 및 기타 경고를 보려면 Show Warnings and errors 를 클릭합니다. 제약 조건 누락을 방지하기 위해 Layout Editor는 자동 연결 및 제약 조건 추론 기능을 사용하여 제약 조건을 자동으로 추가합니다.

ConstraintLayout을 프로젝트에 추가

프로젝트에서 ConstraintLayout를 사용하려면 다음 단계를 진행하세요.

  1. settings.gradle 파일에 maven.google.com 저장소가 선언되어 있는지 확인합니다.

    Groovy

        dependencyResolutionManagement {
          ...
          repositories {
              google()
          }
        )
        

    Kotlin

        dependencyResolutionManagement {
          ...
          repositories {
              google()
          }
        }
        
  2. 다음 예와 같이 모듈 수준 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")
    }
    
  3. 툴바 또는 동기화 알림에서 Sync Project with Gradle Files를 클릭합니다.

이제 ConstraintLayout으로 레이아웃을 빌드할 준비가 되었습니다.

레이아웃 변환

그림 3. 레이아웃을 ConstraintLayout로 변환하는 메뉴

기존 레이아웃을 제약조건 레이아웃으로 변환하려면 다음 단계를 따르세요.

  1. Android 스튜디오에서 레이아웃을 열고 편집기 창 하단에 있는 Design 탭을 클릭합니다.
  2. Component Tree 창에서 레이아웃을 마우스 오른쪽 버튼으로 클릭하고 Convert LinearLayout to ConstraintLayout을 클릭합니다.

새 레이아웃 생성

새 제약조건 레이아웃 파일을 시작하려면 다음 단계를 따르세요.

  1. Project 창에서 모듈 폴더를 클릭하고 File > New > XML > Layout XML을 선택합니다.
  2. 레이아웃 파일의 이름을 입력하고 Root Tag에 "androidx.constraintlayout.widget.ConstraintLayout"을 입력합니다.
  3. Finish를 클릭합니다.

제약조건 추가 또는 삭제

제약조건을 추가하려면 다음 단계를 따르세요.

동영상 1. 뷰의 왼쪽은 상위 요소의 왼쪽으로 제한됩니다.

  1. Palette 창에서 편집기로 보기를 드래그합니다.

    ConstraintLayout에 뷰를 추가하면 각 모서리에 정사각형 크기 조절 핸들과 양쪽에 원형 제약조건 핸들이 있는 경계 상자에 표시됩니다.

  2. 보기를 클릭하여 선택합니다.
  3. 다음 중 한 가지 방법을 사용합니다.
    • 제약조건 핸들을 클릭하여 사용 가능한 앵커 포인트로 드래그합니다. 이 지점은 다른 뷰의 가장자리, 레이아웃의 가장자리 또는 안내선일 수 있습니다. 제약 조건 핸들을 드래그하면 Layout Editor에 잠재적인 연결 앵커와 파란색 오버레이가 표시됩니다.
    • 그림 4와 같이 Attributes 창의 Layout 섹션에서 Create a connection 버튼 중 하나를 클릭합니다.

      그림 4. Attributes 창의 Layout 섹션을 사용하면 연결을 만들 수 있습니다.

제약조건이 생성되면 편집기에서 기본 여백을 지정하여 두 뷰를 분리합니다.

제약조건을 만들 때 다음 규칙을 기억하세요.

  • 모든 뷰에는 가로와 세로로 각각 하나씩 최소 두 개의 제약 조건이 있어야 합니다.
  • 제약조건 핸들과 동일한 평면을 공유하는 앵커 포인트 간에만 제약조건을 만들 수 있습니다. 뷰의 수직 평면(왼쪽과 오른쪽)은 다른 수직 평면으로만 제한될 수 있으며, 기준은 다른 기준선으로만 제한될 수 있습니다.
  • 각 제약조건 핸들은 하나의 제약조건에만 사용할 수 있지만, 여러 보기에서 동일한 앵커 포인트까지 여러 제약조건을 만들 수 있습니다.

다음 중 하나를 실행하여 제약조건을 삭제할 수 있습니다.

  • 제약조건을 클릭하여 선택한 후 삭제를 클릭합니다.
  • 제약조건 앵커를 Control 키를 누른 상태에서 클릭 (macOS에서는 Command 키를 누른 상태에서 클릭)합니다. 그림 5와 같이 제약조건이 빨간색으로 바뀌면 클릭하여 삭제할 수 있음을 나타냅니다.

    그림 5. 빨간색 제약조건은 클릭하여 삭제할 수 있음을 나타냅니다.

  • Attributes 창의 Layout 섹션에서 그림 6과 같이 제약 조건 앵커를 클릭합니다.

    그림 6. 제약조건 앵커를 클릭하여 삭제합니다.

동영상 2. 기존 제약조건에 반대하는 제약조건 추가

뷰에 반대 제약 조건을 추가하면 제약 조건 선이 스프링처럼 감겨져 반대쪽의 힘을 나타냅니다(동영상 2 참고). 이 효과는 뷰 크기가 '고정' 또는 '콘텐츠 래핑'으로 설정될 때 가장 눈에 띄게 표시되며, 이 경우 뷰가 제약 조건 사이의 중앙에 배치됩니다. 대신 제약 조건을 충족하도록 뷰 크기를 늘리려면 '제약 조건과 일치'하도록 크기를 전환하세요. 현재 크기를 유지하면서 뷰가 중앙에 배치되지 않도록 이동하려면 제약조건 편향을 조정하세요.

다음 섹션에 설명된 대로 제약 조건을 사용하여 다양한 유형의 레이아웃 동작을 구현할 수 있습니다.

상위 요소 포지셔닝

뷰의 측면을 레이아웃의 상응하는 가장자리로 제한합니다.

그림 7에서 뷰의 왼쪽은 상위 레이아웃의 왼쪽 가장자리에 연결됩니다. 여백을 사용하여 가장자리로부터의 거리를 정의할 수 있습니다.

그림 7. 상위 요소의 가로 제약 조건입니다.

위치 순서 지정

두 뷰의 표시 순서를 세로 또는 가로로 정의합니다.

그림 8에서 B는 항상 A의 오른쪽에 있도록 제한되고 C는 A 아래로 제한됩니다. 그러나 이러한 제약 조건은 정렬을 의미하지 않으므로 B는 여전히 위아래로 이동할 수 있습니다.

그림 8. 가로 및 세로 제약 조건

정렬

보기의 가장자리를 다른 보기의 가장자리에 맞게 정렬합니다.

그림 9에서 B의 왼쪽은 A의 왼쪽에 맞게 정렬됩니다. 뷰 중심을 정렬하려면 양쪽에 제약 조건을 만듭니다.

제약 조건에서 안쪽으로 보기를 드래그하여 정렬을 오프셋할 수 있습니다. 예를 들어, 그림 10에서는 24dp 오프셋 정렬의 B를 보여줍니다. 오프셋은 제한된 뷰의 여백으로 정의됩니다.

정렬할 뷰를 모두 선택한 다음 툴바에서 정렬 을 클릭하여 정렬 유형을 선택할 수도 있습니다.

그림 9. 가로 정렬 제약조건

그림 10. 오프셋 가로 정렬 제약 조건

기준선 정렬

보기의 텍스트 기준선을 다른 보기의 텍스트 기준선에 맞춥니다.

그림 11에서 B의 첫 번째 줄은 A의 텍스트에 맞게 정렬됩니다.

기준선 제약조건을 만들려면 제한할 텍스트 뷰를 마우스 오른쪽 버튼으로 클릭한 다음 Show Baseline을 클릭합니다. 그런 다음 텍스트 기준선을 클릭하고 선을 다른 기준선으로 드래그합니다.

그림 11. 기준선 정렬 제약조건

안내선으로 제한

뷰를 제한할 수 있고 앱 사용자에게 표시되지 않는 세로 또는 가로 안내선을 추가할 수 있습니다. dp 단위 또는 레이아웃의 가장자리를 기준으로 한 백분율을 기준으로 레이아웃 내에 안내선을 배치할 수 있습니다.

안내선을 만들려면 툴바에서 Guidelines 를 클릭한 후 Add Vertical Guideline 또는 Add Horizontal Guideline을 클릭합니다.

점선을 드래그하여 위치를 조정하고 안내선 가장자리에 있는 원을 클릭하여 측정 모드를 전환합니다.

그림 12. 안내선으로 제한된 뷰

경계선으로 제한

안내선과 마찬가지로 경계선은 보기를 제한할 수 있는 보이지 않는 선입니다. 단, 경계선은 자체 위치를 정의하지 않습니다. 대신 장벽 위치는 내부에 포함된 뷰의 위치를 기반으로 움직입니다. 이는 뷰를 하나의 특정 뷰가 아닌 뷰 세트로 제한하려는 경우에 유용합니다.

예를 들어, 그림 13에서 뷰 C는 배리어의 오른쪽으로 제한됩니다. 경계선은 뷰 A와 뷰 B 모두의 '끝' (또는 왼쪽에서 오른쪽 레이아웃의 오른쪽)으로 설정됩니다. 경계선은 보기 A의 오른쪽이나 보기 B의 오른쪽이 맨 오른쪽에 있는지에 따라 움직입니다.

경계선을 만들려면 다음 단계를 따르세요.

  1. 툴바에서 Guidelines 를 클릭하고 Add Vertical Barrier 또는 Add Horizontal Barrier를 클릭합니다.
  2. Component Tree 창에서 경계선 내부의 원하는 보기를 선택하고 경계선 구성요소로 드래그합니다.
  3. Component Tree에서 경계선을 선택하고 Attributes 창을 연 후 barrierDirection을 설정합니다.

이제 다른 보기에서 경계선으로의 제약조건을 만들 수 있습니다.

경계선 내부의 보기를 경계선으로 제한할 수도 있습니다. 이렇게 하면 어느 뷰가 가장 길거나 가장 높은지 모르더라도 경계선의 모든 뷰를 서로 정렬할 수 있습니다.

경계선의 '최소' 위치를 보장하도록 경계선 안에 안내선도 포함할 수 있습니다.

그림 13. 뷰 C는 뷰 A와 뷰 B 모두의 위치와 크기를 기반으로 이동하는 경계선으로 제한됩니다.

제약조건 편향 조정

뷰의 양쪽에 제약 조건을 추가하고 동일한 크기의 뷰 크기가 '고정' 또는 '콘텐츠 래핑'이면 뷰가 두 제약 조건 사이의 중앙에 배치되고 기본적으로 편향은 50% 입니다. 동영상 3에 표시된 대로 Attributes 창에서 편향 슬라이더를 드래그하거나 보기를 드래그하여 편향을 조정할 수 있습니다.

대신 제약조건에 맞게 보기의 크기를 늘리려면 '제약조건과 일치'하도록 크기를 전환합니다.

동영상 3. 제약 조건 편향 조정

보기 크기 조정

그림 14. 뷰를 선택할 때 Attributes 창에는 크기 비율 1, 제약 조건 삭제 2, 높이 또는 너비 모드 3, 여백 4, 제약 조건 바이어스 5에 관한 컨트롤이 포함됩니다. 또한 6 제약 조건 목록에서 제약 조건을 클릭하여 Layout Editor에서 개별 제약 조건을 강조 표시할 수도 있습니다.

모서리 핸들을 사용하여 뷰의 크기를 조절할 수 있지만 이렇게 하면 크기가 하드 코딩됩니다. 즉, 다른 콘텐츠나 화면 크기에 맞게 뷰의 크기가 조절되지 않습니다. 다른 크기 조정 모드를 선택하려면 뷰를 클릭하고 편집기의 오른쪽에 있는 Attributes 창을 엽니다.

Attributes 창 상단 근처에는 뷰 검사기가 있습니다. 이 검사기에는 그림 14와 같이 여러 레이아웃 속성의 컨트롤이 포함되어 있습니다. 제약 조건 레이아웃의 뷰에만 사용할 수 있습니다.

그림 14에서 콜아웃 3으로 표시된 기호를 클릭하여 높이와 너비를 계산하는 방법을 변경할 수 있습니다. 이러한 기호는 다음과 같이 크기 모드를 나타냅니다. 기호를 클릭하여 다음 설정 간에 전환합니다.

  • 고정: 다음 텍스트 상자에서 특정 크기를 지정하거나 편집기에서 뷰 크기를 조절합니다.
  • 콘텐츠 래핑: 뷰는 콘텐츠에 맞게 필요한 만큼만 확장됩니다.
    • layout_restrictedWidth
    • 제약 조건을 준수하도록 가로 크기가 변경되도록 하려면 true로 설정합니다. 기본적으로 WRAP_CONTENT로 설정된 위젯은 제약 조건으로 제한되지 않습니다.

  • Match Constraints: 뷰의 여백을 고려한 후 뷰가 양쪽의 제약 조건을 충족하도록 최대한 확장됩니다. 그러나 다음 속성과 값을 사용하여 동작을 수정할 수 있습니다. 이러한 속성은 뷰 너비를 '제약 조건과 일치'로 설정한 경우에만 적용됩니다.
    • layout_constraintWidth_min

      보기의 최소 너비에 dp 측정기준을 사용합니다.

    • layout_constraintWidth_max

      보기의 최대 너비에 dp 측정기준을 사용합니다.

    그러나 지정된 크기에 제약조건이 하나만 있으면 보기가 콘텐츠에 맞게 확장됩니다. 높이 또는 너비에서 이 모드를 사용하면 크기 비율을 설정할 수도 있습니다.

크기를 비율로 설정

그림 15. 뷰는 16:9 가로세로 비율로 설정되고 높이 비율에 따라 너비가 설정됩니다.

뷰 크기 중 하나 이상이 '제약조건과 일치'(0dp)로 설정된 경우 뷰 크기를 비율(예: 16:9)으로 설정할 수 있습니다. 비율을 사용 설정하려면 가로세로 비율 제약 조건 전환(그림 14의 콜아웃 1)을 클릭하고 표시되는 입력에 width:height 비율을 입력합니다.

너비와 높이가 모두 '제약 조건과 일치'로 설정된 경우 Toggle Aspect Ratio Constraint를 클릭하여 다른 크기의 비율을 기반으로 어떤 측정기준을 선택할 수 있습니다. 뷰 검사기는 상응하는 가장자리를 실선으로 연결하여 비율로 설정된 크기를 나타냅니다.

예를 들어 양쪽을 '제약 조건과 일치'하도록 설정하는 경우 Toggle Aspect Ratio Constraint를 두 번 클릭하여 너비가 높이 비율이 되도록 설정합니다. 전체 크기는 그림 15와 같이 뷰의 높이에 따라 결정되며 이는 어떤 방식으로든 정의할 수 있습니다.

보기 여백 조정

뷰의 간격을 균일하게 만들려면 툴바에서 Margin 을 클릭하여 레이아웃에 추가하는 각 뷰의 기본 여백을 선택합니다. 기본 여백을 변경하면 이후에 추가하는 뷰에만 적용됩니다.

각 제약조건을 나타내는 줄의 숫자를 클릭하여 Attributes 창에서 각 뷰의 여백을 제어할 수 있습니다. 그림 14에서 콜아웃 4는 하단 여백이 16dp로 설정되어 있음을 보여줍니다.

그림 16. 툴바의 Margin 버튼

도구에서 제공하는 모든 여백은 8dp의 배수로, 뷰가 Material Design의 8dp 정사각형 그리드 권장사항에 맞게 정렬되는 데 도움이 됩니다.

체인이 있는 선형 그룹 제어

그림 17. 두 개의 뷰가 있는 가로 체인

체인은 양방향 위치 제약 조건으로 서로 연결된 뷰 그룹입니다. 체인의 뷰는 세로 또는 가로로 분산될 수 있습니다.

그림 18. 각 체인 스타일의 예

체인 스타일은 다음 방법 중 하나로 지정할 수 있습니다.

  1. 넓히기: 여백을 고려한 후 보기가 고르게 분산됩니다. 이는 기본값입니다.
  2. 내부 확산: 첫 번째 뷰와 마지막 뷰가 체인의 각 끝의 제약 조건에 첨부되고 나머지는 고르게 분산됩니다.
  3. Weighted: 체인이 spread 또는 spread 내부로 설정된 경우 하나 이상의 뷰를 'match constraints' (0dp)로 설정하여 남은 공간을 채울 수 있습니다. 기본적으로 공간은 'match constraints'로 설정된 각 뷰 사이에 균일하게 분산되지만, layout_constraintHorizontal_weightlayout_constraintVertical_weight 속성을 사용하여 각 뷰에 중요도 가중치를 할당할 수 있습니다. 이는 선형 레이아웃layout_weight와 동일한 방식으로 작동합니다. 가중치 값이 가장 높은 뷰가 가장 많은 공간을 차지하고 가중치가 동일한 뷰에는 동일한 크기의 공간이 할당됩니다.
  4. 패킹됨: 여백을 고려한 후에 뷰가 함께 패킹됩니다. 체인의 '헤드' 보기 편향을 변경하여 전체 체인의 편향을 왼쪽 또는 오른쪽 또는 위아래로 조정할 수 있습니다.

체인의 '헤드' 뷰(가로 체인의 가장 왼쪽 뷰(왼쪽에서 오른쪽 레이아웃))와 세로 체인의 최상단 뷰는 XML로 체인의 스타일을 정의합니다. 그러나 체인에서 뷰를 선택하고 뷰 아래에 표시되는 체인 버튼 을 클릭하여 넓히기, 내부로 넓히기, 패킹됨 간에 전환할 수 있습니다.

체인을 만들려면 동영상 4와 같이 다음을 수행합니다.

  1. 체인에 포함할 모든 보기를 선택합니다.
  2. 보기 중 하나를 마우스 오른쪽 버튼으로 클릭합니다.
  3. 체인점을 선택합니다.
  4. Center Horizontally 또는 Center Vertically를 선택합니다.

동영상 4. 가로 체인 만들기

다음은 체인을 사용할 때 고려해야 할 몇 가지 사항입니다.

  • 뷰는 가로 및 세로 체인의 일부가 될 수 있으므로 유연한 그리드 레이아웃을 빌드할 수 있습니다.
  • 그림 14와 같이 체인의 각 끝이 동일한 축의 다른 객체로 제한된 경우에만 체인이 제대로 작동합니다.
  • 체인의 방향이 세로 또는 가로이지만 체인을 사용한다고 해서 보기가 해당 방향으로 정렬되지 않습니다. 체인에서 각 뷰의 적절한 위치를 얻으려면 정렬 제약 조건과 같은 다른 제약 조건을 포함합니다.

자동으로 제약조건 만들기

레이아웃에 배치할 때 모든 뷰에 제약 조건을 추가하는 대신, Layout Editor에서 원하는 위치로 각 뷰를 이동한 다음 Infer Constraints 를 클릭하여 제약 조건을 자동으로 생성할 수 있습니다.

Infer Constraints는 레이아웃을 검사하여 모든 뷰에 가장 효과적인 제약 조건 집합을 결정합니다. 뷰를 현재 위치로 제한하면서 유연성을 제공합니다. 다양한 화면 크기와 방향에 의도한 대로 레이아웃이 반응하도록 조정해야 할 수 있습니다.

상위 항목과 자동 연결은 별도로 사용 설정할 수 있습니다. 이 기능을 사용 설정하고 상위 요소에 하위 뷰를 추가하면 레이아웃에 뷰를 추가할 때 뷰마다 제약 조건이 두 개 이상 자동으로 생성됩니다. 단, 뷰를 상위 레이아웃으로 제한하는 것이 적합한 경우에만 생성됩니다. 자동 연결은 레이아웃의 다른 뷰에 관한 제약 조건을 생성하지 않습니다.

자동 연결은 기본적으로 사용되지 않습니다. Layout Editor 툴바에서 Enable Autoconnection to Parent 를 클릭하여 사용 설정합니다.

키프레임 애니메이션

ConstraintLayout 내에서 ConstraintSetTransitionManager를 사용하여 요소의 크기 및 위치 변경사항을 애니메이션으로 표시할 수 있습니다.

ConstraintSetConstraintLayout 내 모든 하위 요소의 제약 조건, 여백, 패딩을 나타내는 경량 객체입니다. 표시된 ConstraintLayoutConstraintSet를 적용하면 레이아웃에서 모든 하위 요소의 제약 조건을 업데이트합니다.

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>

추가 리소스

ConstraintLayoutSunflower 데모 앱에서 사용됩니다.