Android 卡片循环切换动画

25 阅读1分钟

效果图

video -original-original.gif

布局代码

       <FrameLayout
           android:paddingHorizontal="@dimen/dp_13"
           android:id="@+id/frame"
           android:layout_width="match_parent"
           android:layout_height="@dimen/dp_353">
           
           <com.hjq.shape.layout.ShapeLinearLayout
               android:layout_width="match_parent"
               app:shape_solidColor="@color/blue"
               app:shape_radius="@dimen/dp_32"
               android:translationY="@dimen/dp_101"
               android:layout_height="@dimen/dp_252"/>

           <com.hjq.shape.layout.ShapeLinearLayout
               android:layout_width="match_parent"
               app:shape_solidColor="@color/red"
               app:shape_radius="@dimen/dp_32"
               android:translationY="@dimen/dp_50"
               android:layout_height="@dimen/dp_252"/>

           <com.hjq.shape.layout.ShapeLinearLayout
               android:layout_width="match_parent"
               app:shape_solidColor="@color/green"
               app:shape_radius="@dimen/dp_32"
               android:layout_height="@dimen/dp_252"/>
       </FrameLayout>

核心代码


override fun initData() {
        // 初始化视图列表(按Z轴顺序)
        views.add(mLlGj)
        views.add(mLlZb)
        views.add(mLlHj)

        // 设置点击监听
        views.forEach { view ->
            view.setOnClickListener {
                if (!isAnimating) {
                    cycleViews(views.indexOf(view))
                }
            }
        }
    }


    private fun cycleViews(position: Int) {
        if (position == 0) return

        isAnimating = true
        val duration = 400L
        val interpolator = OvershootInterpolator(1.5f)

        views.forEachIndexed { index, view ->
            if (index == position) {
                view.elevation = 6f.dp
            } else{
                view.elevation = 2f.dp
            }
        }

        if (position == 1) {
            // 中间层动画
            views[1].animate()
                .translationY(0f)
                .setDuration(duration)
                .setInterpolator(interpolator)
                .start()

            // 原顶层动画
            views.first().animate()
                .translationY(50f.dp)
                .setDuration(duration)
                .setInterpolator(interpolator)
                .withEndAction {
                    views.add(0, views.removeAt(position))
                    resetViewElevation()
                    isAnimating = false
                }
                .start()

        } else if (position == 2) {
            // 移动底层到顶层
            views.last().animate()
                .translationY(0f)
                .setDuration(duration)
                .setInterpolator(interpolator)
                .start()

            // 中间层动画
            views[1].animate()
                .translationY(101f.dp)
                .setDuration(duration)
                .setInterpolator(interpolator)
                .start()

            // 原顶层动画
            views.first().animate()
                .translationY(50f.dp)
                .setDuration(duration)
                .setInterpolator(interpolator)
                .withEndAction {
                    views.add(0, views.removeAt(position))
                    resetViewElevation()
                    isAnimating = false
                }
                .start()
        }
    }

    private fun resetViewElevation() {
        // 根据层级重新设置Elevation
        views.forEachIndexed { index, view ->
            view.elevation = when(index) {
                0 -> 6f.dp
                1 -> 4f.dp
                else -> 2f.dp
            }
        }
    }