【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>
相关推荐
m0_548514774 小时前
2024.12.10——攻防世界Web_php_include
android·前端·php
凤邪摩羯4 小时前
Android-性能优化-03-启动优化-启动耗时
android
凤邪摩羯4 小时前
Android-性能优化-02-内存优化-LeakCanary原理解析
android
喀什酱豆腐5 小时前
Handle
android
m0_748232926 小时前
Android Https和WebView
android·网络协议·https
m0_748251726 小时前
Android webview 打开本地H5项目(Cocos游戏以及Unity游戏)
android·游戏·unity
m0_748254668 小时前
go官方日志库带色彩格式化
android·开发语言·golang
zhangphil8 小时前
Android使用PorterDuffXfermode模式PorterDuff.Mode.SRC_OUT橡皮擦实现“刮刮乐”效果,Kotlin(2)
android·kotlin
爱学测试的李木子9 小时前
从0到1搭建 Android 自动化 python+appium 环境
android·软件测试·python·测试工具·自动化
咸芝麻鱼9 小时前
Android Studio | 连接手机设备后,启动App时出现:Waiting For DebuggerApplication (App名)...
android·adb·智能手机·android studio