Android应用中目标动画的名称、归属及实现方案咨询
卡片折叠/展开视差动画解析与实现
动画名称
这个动画属于带视差效果的卡片折叠/展开过渡动画,核心是头部区域的位移视差+内容区的渐显/位移联动效果。
是否为Android Material原生动画
不属于Material Design原生标准动画。Material仅提供了基础的折叠/展开动效(如ExpandableLayout的简单过渡、MotionLayout基础约束动画),但这种多元素联动的视差+分步渐显效果需要自定义实现。
实现方案(Android)
核心思路
采用MotionLayout作为容器,通过定义ConstraintSet控制折叠/展开状态,配合关键帧动画实现多元素的流畅联动,这是实现此类复杂过渡动画最稳定的方式。
具体步骤
布局结构
用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>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>代码触发动画
在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
相关产品推荐
相关产品推荐

