【Android】MotionLayout Carousel

MotionLayout之Carousel

xml 复制代码
<androidx.constraintlayout.helper.widget.Carousel
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/Carousel"
    app:carousel_previousState="@id/previous"
    app:carousel_forwardTransition="@id/forward"
    app:carousel_nextState="@id/next"
    app:carousel_backwardTransition="@id/backward"
    app:carousel_firstView="@id/view2"
    app:carousel_infinite="true"
    app:constraint_referenced_ids="view1,view2,view3,view4,view5"
    >

</androidx.constraintlayout.helper.widget.Carousel>

我们假设:向上滑动是显示后一个,向下滑动是显示前一个

  • previousState:当向下滑动要显示前一个时,且滑动完毕后的状态
  • nextState:当向上滑动要显示后一个时,且滑动完毕后的状态
  • forwardTransition:当向下滑动要显示前一个时,这个过程的动画效果
  • backwardTransition:当向上滑动要显示后一个时,这个过程的动画效果
  • firstView:表示当index=0时,指的是哪一个view。
  • constraint_referenced_ids:这个顺序也不能乱写,这个例子的意思是:view1是作为view2的前一个view,view1的index值就是4,因为我们使用adapter设置的count数是5,也就是0-4,又因为是循环显示:所以值无法是-1,只能是4,以此类推,view3的index是1,view4的index是2,view5的index是3.

adapter

java 复制代码
/**
 * Adapter for a Carousel
 */
public interface Adapter {
    /**
     * Number of items you want to display in the Carousel
     * @return number of items
     */
    int count();

    /**
     * Callback to populate the view for the given index
     *
     * @param view
     * @param index
     */
    void populate(View view, int index);

    /**
     * Callback when we reach a new index
     * @param index
     */
    void onNewItem(int index);
}

这里的count返回值表示,我们view的index的最大值就是count-1,我觉得这里的显示的数量表示不准确,不如说:一个显示周期的item个数。因为这个值无法控制显示的个数。

比如我们有5个view:view1,view2,view3,view4,view5

count返回值: 3

firstView: view1

那么对应的index就是

makefile 复制代码
view1:  0

view2:  1

view3:  2
    
view4:  0

view5:  1

关于index的计算公式在Carousel中也有。

java 复制代码
private void updateItems() {
    
    final int viewCount = mList.size();
    for (int i = 0; i < viewCount; i++) {
        View view = mList.get(i);
        //mIndex表示当前显示的index,这个index是按实际显示的位置来的,默认不滑动时,mIndex就等于0
        int index = mIndex + i - mStartIndex;//当view5时:index = 0+4-0 = 4 
        if (mInfiniteCarousel) {
            if (index < 0) {
                if (mEmptyViewBehavior != View.INVISIBLE) {
                    updateViewVisibility(view, mEmptyViewBehavior);
                } else {
                    updateViewVisibility(view, VISIBLE);
                }
                if (index % mAdapter.count() == 0) {
                    mAdapter.populate(view, 0);
                } else {
                    mAdapter.populate(view, mAdapter.count() + (index % mAdapter.count()));
                }
            } else if (index >= mAdapter.count()) {//大于count了,
                if (index == mAdapter.count()) {
                    index = 0;//重回0
                } else if (index > mAdapter.count()) {//index=4,
                    index = index % mAdapter.count();//index = 4%3=1
                }
                if (mEmptyViewBehavior != View.INVISIBLE) {
                    updateViewVisibility(view, mEmptyViewBehavior);
                } else {
                    updateViewVisibility(view, VISIBLE);
                }
                mAdapter.populate(view, index);
            } else {
                updateViewVisibility(view, VISIBLE);
                mAdapter.populate(view, index);
            }
        } 
     }  
}

populate表示:从index 0到4之间,移动到目标位置后index 0-4都会执行一次populate,因为view在parent的位置没有改变,我们改变的只是index的值,所以对于同一个view,他的index值已经改变,我们需要确定下,在当前位置该view需要再设置成什么样式。当这些操作完成后会再执行一次onNewItem表示我们当前的这一个操作已经完成。

也就是说我们向前滑动完成后,view1的状态需要更新成上一次view5的状态了。

切记 view在父view中的位置没有改变,变得只是对应的index值,比如这里的firstView值是view3,他的初始index是0,当完成一次向上移动时,他的index就变成1了。

附上我自己的scene文件,

xml 复制代码
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <Transition
        android:id="@+id/forward"
        app:constraintSetEnd="@+id/next"
        app:constraintSetStart="@+id/start">

        <OnSwipe app:dragDirection="dragUp" />

        <KeyFrameSet>

            <KeyPosition
                app:framePosition="50"
                app:keyPositionType="parentRelative"
                app:motionTarget="@id/view3"
                app:percentY="0.1">

            </KeyPosition>

        </KeyFrameSet>

    </Transition>

    <Transition
        android:id="@+id/backward"
        app:constraintSetEnd="@+id/previous"
        app:constraintSetStart="@+id/start">

        <OnSwipe app:dragDirection="dragDown" />
        <KeyFrameSet>
            <KeyPosition
                app:framePosition="50"
                app:keyPositionType="parentRelative"
                app:motionTarget="@id/view3"
                app:percentY="0.9">

            </KeyPosition>
        </KeyFrameSet>

    </Transition>


    <ConstraintSet android:id="@+id/start">


        <Constraint
            android:id="@id/view1"
            android:layout_width="100dp"
            android:layout_height="300dp"
            android:rotation="-30"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent">

        </Constraint>

        <Constraint
            android:id="@id/view2"
            android:layout_width="100dp"
            android:layout_height="300dp"
            android:rotation="-15"
            android:translationZ="2dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent">

        </Constraint>
        <Constraint
            android:id="@id/view3"
            android:layout_width="100dp"
            android:layout_height="300dp"
            android:rotation="0"
            android:translationZ="4dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent">

        </Constraint>
        <Constraint
            android:id="@id/view4"
            android:layout_width="100dp"
            android:layout_height="300dp"
            android:rotation="15"
            android:translationZ="2dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent">

        </Constraint>
        <Constraint
            android:id="@id/view5"
            android:layout_width="100dp"
            android:layout_height="300dp"
            android:rotation="30"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent">

        </Constraint>


    </ConstraintSet>


    <ConstraintSet android:id="@+id/previous">
        <Constraint
            android:id="@id/view1"
            android:layout_width="100dp"
            android:layout_height="300dp"
            android:rotation="-15"
            android:translationZ="2dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent">

        </Constraint>

        <Constraint
            android:id="@id/view2"
            android:layout_width="100dp"
            android:layout_height="300dp"
            android:rotation="0"
            android:translationZ="4dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent">

        </Constraint>
        <Constraint
            android:id="@id/view3"
            android:layout_width="100dp"
            android:layout_height="300dp"
            android:rotation="15"
            android:translationZ="2dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent">

        </Constraint>
        <Constraint
            android:id="@id/view4"
            android:layout_width="100dp"
            android:layout_height="300dp"
            android:rotation="30"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent">

        </Constraint>
        <Constraint
            android:id="@id/view5"
            android:layout_width="100dp"
            android:layout_height="300dp"
            android:rotation="-30"
            android:translationZ="-2dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent">

        </Constraint>
    </ConstraintSet>

    <ConstraintSet android:id="@+id/next">
        <Constraint
            android:id="@id/view1"
            android:layout_width="100dp"
            android:layout_height="300dp"
            android:rotation="30"
            android:translationZ="-2dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent">

        </Constraint>

        <Constraint
            android:id="@id/view2"
            android:layout_width="100dp"
            android:layout_height="300dp"
            android:rotation="-30"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent">

        </Constraint>
        <Constraint
            android:id="@id/view3"
            android:layout_width="100dp"
            android:layout_height="300dp"
            android:rotation="-15"
            android:translationZ="2dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent">

        </Constraint>
        <Constraint
            android:id="@id/view4"
            android:layout_width="100dp"
            android:layout_height="300dp"
            android:rotation="0"
            android:translationZ="4dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent">

        </Constraint>
        <Constraint
            android:id="@id/view5"
            android:layout_width="100dp"
            android:layout_height="300dp"
            android:rotation="15"
            android:translationZ="2dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent">

        </Constraint>
    </ConstraintSet>


</MotionScene>
相关推荐
手机不死我是天子1 小时前
《Android 核心组件深度系列 · 第 2 篇 Service》
android
前行的小黑炭1 小时前
Compose页面切换的几种方式:Navigation、NavigationBar+HorizontalPager,会导致LaunchedEffect执行?
android·kotlin·app
前行的小黑炭2 小时前
Android :Comnpose各种副作用的使用
android·kotlin·app
BD_Marathon15 小时前
【MySQL】函数
android·数据库·mysql
西西学代码16 小时前
安卓开发---耳机的按键设置的UI实例
android·ui
maki07720 小时前
虚幻版Pico大空间VR入门教程 05 —— 原点坐标和项目优化技巧整理
android·游戏引擎·vr·虚幻·pico·htc vive·大空间
千里马学框架21 小时前
音频焦点学习之AudioFocusRequest.Builder类剖析
android·面试·智能手机·车载系统·音视频·安卓framework开发·audio
fundroid1 天前
掌握 Compose 性能优化三步法
android·android jetpack
TeleostNaCl1 天前
如何在 IDEA 中使用 Proguard 自动混淆 Gradle 编译的Java 项目
android·java·经验分享·kotlin·gradle·intellij-idea
旷野说1 天前
Android Studio Narwhal 3 特性
android·ide·android studio