You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android应用中目标动画的名称、归属及实现方案咨询

卡片折叠/展开视差动画解析与实现

动画名称

这个动画属于带视差效果的卡片折叠/展开过渡动画,核心是头部区域的位移视差+内容区的渐显/位移联动效果。

是否为Android Material原生动画

不属于Material Design原生标准动画。Material仅提供了基础的折叠/展开动效(如ExpandableLayout的简单过渡、MotionLayout基础约束动画),但这种多元素联动的视差+分步渐显效果需要自定义实现。

实现方案(Android)

核心思路

采用MotionLayout作为容器,通过定义ConstraintSet控制折叠/展开状态,配合关键帧动画实现多元素的流畅联动,这是实现此类复杂过渡动画最稳定的方式。

具体步骤

  1. 布局结构
    用MotionLayout包裹头部视图(如ImageView)和内容容器:

    <androidx.constraintlayout.motion.widget.MotionLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/card_motion_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layoutDescription="@xml/card_motion_scene">
    
        <!-- 头部视差区域 -->
        <ImageView
            android:id="@+id/card_header"
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:scaleType="centerCrop"
            android:src="@drawable/card_header_bg"/>
    
        <!-- 内容区域 -->
        <LinearLayout
            android:id="@+id/card_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:padding="16dp"
            android:alpha="0">
    
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="标题文本"
                android:textSize="18sp"
                android:textStyle="bold"/>
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="多行内容示例,动画展开时会逐步显示"
                android:layout_marginTop="8dp"/>
        </LinearLayout>
    </androidx.constraintlayout.motion.widget.MotionLayout>
    
  2. MotionScene配置
    在res/xml/card_motion_scene.xml中定义两种状态及过渡动画:

    <MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    
        <!-- 折叠状态 -->
        <ConstraintSet android:id="@+id/state_collapsed">
            <Constraint
                android:id="@+id/card_header"
                android:layout_width="match_parent"
                android:layout_height="120dp"
                app:layout_constraintTop_toTopOf="parent"/>
            <Constraint
                android:id="@+id/card_content"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:alpha="0"
                app:layout_constraintTop_toBottomOf="@id/card_header"/>
        </ConstraintSet>
    
        <!-- 展开状态 -->
        <ConstraintSet android:id="@+id/state_expanded">
            <Constraint
                android:id="@+id/card_header"
                android:layout_width="match_parent"
                android:layout_height="200dp"
                app:layout_constraintTop_toTopOf="parent"/>
            <Constraint
                android:id="@+id/card_content"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:alpha="1"
                app:layout_constraintTop_toBottomOf="@id/card_header"/>
        </ConstraintSet>
    
        <!-- 过渡动画配置 -->
        <Transition
            app:constraintSetStart="@id/state_collapsed"
            app:constraintSetEnd="@id/state_expanded"
            app:duration="350"
            app:motionInterpolator="accelerateDecelerate">
    
            <!-- 头部视差位移关键帧 -->
            <KeyFrameSet>
                <KeyAttribute
                    android:attributeName="translationY"
                    app:framePosition="40"
                    app:target="@id/card_header"
                    android:value="-15dp"/>
            </KeyFrameSet>
    
            <!-- 内容区渐显+位移动画 -->
            <KeyAttribute
                android:attributeName="alpha"
                app:framePosition="25"
                app:target="@id/card_content"
                android:value="0"/>
            <KeyAttribute
                android:attributeName="alpha"
                app:framePosition="75"
                app:target="@id/card_content"
                android:value="1"/>
            <KeyAttribute
                android:attributeName="translationY"
                app:framePosition="0"
                app:target="@id/card_content"
                android:value="20dp"/>
            <KeyAttribute
                android:attributeName="translationY"
                app:framePosition="100"
                app:target="@id/card_content"
                android:value="0"/>
        </Transition>
    </MotionScene>
    
  3. 代码触发动画
    在Activity或Fragment中添加点击切换逻辑:

    val motionLayout = findViewById<MotionLayout>(R.id.card_motion_layout)
    var isExpanded = false
    
    motionLayout.setOnClickListener {
        isExpanded = !isExpanded
        val targetState = if (isExpanded) R.id.state_expanded else R.id.state_collapsed
        motionLayout.transitionToState(targetState)
    }
    

流畅性优化要点

  • 优先使用MotionLayout:它基于约束系统实现动画,比传统ObjectAnimator性能更高,避免过度绘制导致的卡顿。
  • 控制动画时长:300-400ms的时长符合Material Design动效节奏,既自然又不会拖沓。
  • 头部图片优化:使用centerCrop或centerInside的scaleType,避免动画过程中图片重绘。

内容的提问来源于stack exchange,提问作者htfi Lo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 07:44:51