Android中使用MotionLayout实现指定动画遇到问题求助
MotionLayout实现底部上滑联动动画方案
目标动画说明
底部内容区域向上滑动时,顶部导航栏从紧凑状态展开为高栏,同时显示展开式标题,底部内容同步上移至导航栏下方,整体过渡平滑连贯。
核心实现思路
通过MotionLayout的ConstraintSet定义初始(收缩)和目标(展开)两个关键帧状态,配合MotionScene配置过渡动画规则,绑定滚动事件触发动画,实现视图间的联动效果。
具体代码实现
1. 主布局文件(activity_main.xml)
<?xml version="1.0" encoding="utf-8"?> <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/motion_layout" android:layout_width="match_parent" android:layout_height="match_parent" app:layoutDescription="@xml/motion_scene"> <!-- 顶部导航栏 --> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="@color/white" app:title="收缩状态"> <TextView android:id="@+id/expanded_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="展开状态标题" android:textSize="24sp" android:visibility="gone"/> </androidx.appcompat.widget.Toolbar> <!-- 底部可滚动内容区域 --> <androidx.core.widget.NestedScrollView android:id="@+id/content_scroll" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_constraintBottom_toBottomOf="parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="16dp"> <!-- 填充足够多的内容使视图可滚动 --> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="内容项 1" android:textSize="18sp" android:paddingVertical="12dp"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="内容项 2" android:textSize="18sp" android:paddingVertical="12dp"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="内容项 3" android:textSize="18sp" android:paddingVertical="12dp"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="内容项 4" android:textSize="18sp" android:paddingVertical="12dp"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="内容项 5" android:textSize="18sp" android:paddingVertical="12dp"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="内容项 6" android:textSize="18sp" android:paddingVertical="12dp"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="内容项 7" android:textSize="18sp" android:paddingVertical="12dp"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="内容项 8" android:textSize="18sp" android:paddingVertical="12dp"/> </LinearLayout> </androidx.core.widget.NestedScrollView> </androidx.constraintlayout.motion.widget.MotionLayout>
2. MotionScene配置文件(res/xml/motion_scene.xml)
<?xml version="1.0" encoding="utf-8"?> <MotionScene xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <!-- 初始收缩状态 --> <ConstraintSet android:id="@+id/start"> <Constraint android:id="@id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_constraintTop_toTopOf="parent"/> <Constraint android:id="@id/expanded_title" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintMarginStart="16dp"> <PropertySet android:alpha="0" android:visibility="invisible"/> </Constraint> <Constraint android:id="@id/content_scroll" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_constraintBottom_toBottomOf="parent"> <CustomAttribute app:attributeName="translationY" app:customFloatValue="200dp"/> <!-- 初始偏移,模拟底部悬浮状态 --> </Constraint> </ConstraintSet> <!-- 目标展开状态 --> <ConstraintSet android:id="@+id/end"> <Constraint android:id="@id/toolbar" android:layout_width="match_parent" android:layout_height="120dp" app:layout_constraintTop_toTopOf="parent"/> <Constraint android:id="@id/expanded_title" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintMarginStart="16dp" app:layout_constraintMarginTop="40dp"> <PropertySet android:alpha="1" android:visibility="visible"/> </Constraint> <Constraint android:id="@id/content_scroll" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_constraintTop_toBottomOf="@id/toolbar" app:layout_constraintBottom_toBottomOf="parent"> <CustomAttribute app:attributeName="translationY" app:customFloatValue="0dp"/> </Constraint> </ConstraintSet> <!-- 过渡动画规则 --> <Transition app:constraintSetStart="@id/start" app:constraintSetEnd="@id/end" app:duration="500" app:motionInterpolator="linear"> <!-- 绑定滚动触发动画 --> <OnSwipe app:touchAnchorId="@id/content_scroll" app:touchAnchorSide="top" app:dragDirection="dragUp"/> <!-- 标题显隐的渐变动画 --> <KeyFrameSet> <KeyAttribute android:alpha="0" app:motionTarget="@id/expanded_title" app:framePosition="0"/> <KeyAttribute android:alpha="1" app:motionTarget="@id/expanded_title" app:framePosition="100"/> </KeyFrameSet> </Transition> </MotionScene>
常见问题排查
- 动画卡顿:确保
NestedScrollView内容不要过于复杂,或在对应Activity的Manifest配置中添加android:hardwareAccelerated="true"开启硬件加速。 - 滚动联动失效:检查
MotionScene中OnSwipe的touchAnchorId是否指向可滚动视图,dragDirection是否匹配滑动方向,同时确认MotionLayout的layoutDescription路径正确。 - 视图显隐异常:在
PropertySet中同时配置alpha和visibility属性,避免单一属性导致的视觉闪烁。
内容的提问来源于stack exchange,提问作者Abhay
相关产品推荐
相关产品推荐

