Карусель с MotionLayout

Carousel — это вспомогательный объект движения для создания пользовательских представлений карусели, которые показывают список элементов, которые пользователь может просмотреть. По сравнению с другими способами реализации таких представлений, этот помощник позволяет быстро создавать сложные изменения движения и размеров для вашей Carousel , используя преимущества MotionLayout .

Виджет Carousel поддерживает списки с началом и концом, а также циклические списки.

Как работает карусель с MotionLayout

Предположим, вы хотите создать горизонтальную Carousel с увеличенным центральным элементом:

Этот базовый макет содержит несколько представлений, представляющих элементы Carousel :

Создайте MotionLayout со следующими тремя состояниями и присвойте им идентификаторы:

  • предыдущий
  • начинать
  • следующий

Если начальное состояние соответствует базовому макету, в предыдущем и следующем состояниях элементы Carousel смещаются на единицу влево и вправо соответственно.

Например, возьмем пять представлений на рис. 3 и предположим, что в начальном состоянии виды B, C и D видимы, а A и E находятся за пределами экрана. Настройте предыдущее состояние так, чтобы позиции A, B, C и D были там, где были B, C, D и E, а виды перемещались слева направо. В следующем состоянии должно произойти обратное: B, C, D и E перемещаются туда, где были A, B, C и D, а виды перемещаются справа налево. Это показано на рисунке 4:

Крайне важно, чтобы представления заканчивались именно там, где начинались исходные представления. Carousel создает иллюзию бесконечной коллекции элементов, перемещая фактические представления обратно туда, где они были, но повторно инициализируя их с новым соответствующим содержимым. На следующей диаграмме показан этот механизм. Обратите внимание на значения «item #»):

Переходы

Используя эти три набора ограничений, определенные в файле сцены движения, создайте два перехода — вперед и назад — между начальным и следующим состояниями, а также начальным и предыдущим состояниями. Добавьте обработчик 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 предыдущего состояния.
  • app:carousel_nextState : идентификатор ConstraintSet следующего состояния.
  • app:carousel_backwardTransition : идентификатор Transition , применяемый между начальным и предыдущим состояниями.
  • app:carousel_forwardTransition : идентификатор Transition , применяемый между начальным и следующим состояниями.

Например, в вашем 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 в коде:

Котлин

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.
            }
        })

Ява

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 . Помощник Carousel сделает это автоматически. По умолчанию в таких ситуациях эти представления помечаются как View.INVISIBLE , поэтому общий макет не меняется.

Доступен альтернативный режим, в котором помощник Carousel вместо этого помечает эти представления как View.GONE . Вы можете установить этот режим, используя следующее свойство:

app:carousel_emptyViewsBehavior="gone"

Примеры

Дополнительные примеры использования помощника Carousel см. в примерах проектов на GitHub.