MotionLayout으로 캐러셀

Carousel는 사용자가 훑어볼 수 있는 요소 목록을 표시하는 맞춤 캐러셀 뷰를 빌드하는 모션 도우미 객체입니다. 이러한 뷰를 구현하는 다른 방법과 비교할 때 이 도우미를 사용하면 MotionLayout를 활용하여 Carousel의 복잡한 모션 및 크기 변경사항을 빠르게 만들 수 있습니다.

Carousel 위젯은 시작과 끝이 있는 목록과 순환 래핑 목록을 지원합니다.

MotionLayout을 사용한 캐러셀의 작동 방식

가운데 항목을 확대하여 가로 Carousel 뷰를 빌드한다고 가정해 보겠습니다.

이 기본 레이아웃에는 Carousel 항목을 나타내는 여러 뷰가 포함되어 있습니다.

다음 세 가지 상태로 MotionLayout를 만들고 ID를 제공합니다.

  • 이전
  • 시작
  • 다음

start 상태가 기본 레이아웃에 해당하는 경우 이전 상태와 다음 상태에서 Carousel 항목은 각각 왼쪽과 오른쪽으로 하나씩 이동합니다.

예를 들어 그림 3의 뷰 5개를 시작 상태에서 뷰 B, C, D가 표시되고 A와 E가 화면 외부에 있다고 가정합니다. A, B, C, D의 위치가 B, C, D, E가 되고 뷰가 왼쪽에서 오른쪽으로 이동하도록 이전 상태를 설정합니다. 다음 상태에서는 B, C, D, E가 A, B, C, D로 이동하고 뷰는 오른쪽에서 왼쪽으로 이동해야 합니다. 그림 4는 다음과 같습니다.

조회수가 원래 보기의 시작 지점으로 정확히 끝나는 것이 중요합니다. Carousel실제 뷰를 원래 위치로 이동하지만 일치하는 새 콘텐츠로 해당 뷰를 다시 초기화하여 요소가 무한히 모여 있는 것처럼 보입니다. 다음 다이어그램은 이 메커니즘을 보여줍니다. '상품 번호' 값에 주의하세요.

화면전환

모션 장면 파일에 정의된 이러한 세 개의 제약 조건 집합을 사용하여 시작다음 상태와 시작이전 상태 사이에 정방향과 역방향 전환 두 개를 생성합니다. 다음 예와 같이 OnSwipe 핸들러를 추가하여 동작에 관한 응답으로 전환을 트리거합니다.

    <Transition
        motion:constraintSetStart="@id/start"
        motion:constraintSetEnd="@+id/next"
        motion:duration="1000"
        android:id="@+id/forward">
        <OnSwipe
            motion:dragDirection="dragLeft"
            motion:touchAnchorSide="left" />
    </Transition>

    <Transition
        motion:constraintSetStart="@+id/start"
        motion:constraintSetEnd="@+id/previous"
        android:id="@+id/backward">
        <OnSwipe
            motion:dragDirection="dragRight"
            motion:touchAnchorSide="right" />
    </Transition>

이 기본 모션 장면을 만든 후 Carousel 도우미를 레이아웃에 추가하고 이전 및 다음 애니메이션을 구현하는 순서와 동일한 순서로 뷰를 참조합니다.

Carousel 도우미에 다음 속성을 설정합니다.

  • app:carousel_firstView: Carousel의 첫 번째 요소를 나타내는 뷰입니다. 이 예에서는 C입니다.
  • app:carousel_previousState: 이전 상태의 ConstraintSet ID입니다.
  • app:carousel_nextState: 다음 상태의 ConstraintSet ID입니다.
  • app:carousel_backwardTransition: 시작이전 상태 사이에 적용된 Transition ID입니다.
  • app:carousel_forwardTransition: 시작 상태와 다음 상태 사이에 적용된 Transition ID입니다.

예를 들어, 레이아웃 XML 파일에 다음과 같은 내용이 있습니다.

    <androidx.constraintlayout.motion.widget.MotionLayout ... >

        <ImageView  android:id="@+id/imageView0" .. />
        <ImageView  android:id="@+id/imageView1" .. />
        <ImageView  android:id="@+id/imageView2" .. />
        <ImageView  android:id="@+id/imageView3" .. />
        <ImageView  android:id="@+id/imageView4" .. />

        <androidx.constraintlayout.helper.widget.Carousel
            android:id="@+id/carousel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:carousel_forwardTransition="@+id/forward"
            app:carousel_backwardTransition="@+id/backward"
            app:carousel_previousState="@+id/previous"
            app:carousel_nextState="@+id/next"
            app:carousel_infinite="true"
            app:carousel_firstView="@+id/imageView2"
            app:constraint_referenced_ids="imageView0,imageView1,imageView2,imageView3,imageView4" />

    </androidx.constraintlayout.motion.widget.MotionLayout>

코드에서 Carousel 어댑터를 설정합니다.

Kotlin

carousel.setAdapter(object : Carousel.Adapter {
            override fun count(): Int {
              // Return the number of items in the Carousel.
            }

            override fun populate(view: View, index: Int) {
                // Implement this to populate the view at the given index.
            }

            override fun onNewItem(index: Int) {
                // Called when an item is set.
            }
        })

Java

carousel.setAdapter(new Carousel.Adapter() {
            @Override
            public int count() {
                // Return the number of items in the Carousel.
            }

            @Override
            public void populate(View view, int index) {
                // Populate the view at the given index.
            }

            @Override
            public void onNewItem(int index) {
                 // Called when an item is set.
            }
        });

추가 참고사항

Carousel에서 '선택됨'의 현재 항목에 따라 Carousel startend를 올바르게 고려하기 위해 이전 또는 이후의 항목을 나타내는 뷰를 숨겨야 할 수도 있습니다. Carousel 도우미가 이 작업을 자동으로 처리합니다. 기본적으로 이러한 상황에서는 뷰를 View.INVISIBLE로 표시하므로 전체 레이아웃은 변경되지 않습니다.

Carousel 도우미가 이러한 뷰를 View.GONE로 대신 표시하는 대체 모드를 사용할 수 있습니다. 이 모드는 다음 속성을 사용하여 설정할 수 있습니다.

app:carousel_emptyViewsBehavior="gone"

캐러셀 도우미를 사용하는 더 많은 예는 GitHub의 프로젝트 예를 참고하세요.