Android Studio MotionLayout无法同时对两个元素执行过渡动画问题求助
问题根因
- MotionLayout仅能控制自身直接子View的属性动画,你当前把
dashboard放在外层普通ConstraintLayout中,仅把swipeUpPic放在MotionLayout内部,所以MotionScene中对dashboard的约束配置、跨布局的关联动画全部不会生效 - 直接给dashboard设置触摸监听器会消费触摸事件,导致MotionLayout原有过渡逻辑被拦截
修复方案
第一步:调整主布局结构
将需要动画的所有控件放到同一个MotionLayout下,直接将根布局替换为MotionLayout即可,无需拆分独立的小MotionLayout:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/white" app:layoutDescription="@xml/activity_main_scene" tools:context=".MainActivity"> <androidx.cardview.widget.CardView android:id="@+id/dashboard" android:layout_width="match_parent" android:layout_height="500dp" app:cardBackgroundColor="@color/green" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent"> </androidx.cardview.widget.CardView> <ImageView android:id="@+id/swipeUpPic" android:layout_width="match_parent" android:layout_height="100dp" android:elevation="20dp" app:layout_constraintBottom_toBottomOf="@id/dashboard" app:layout_constraintEnd_toEndOf="@id/dashboard" app:layout_constraintStart_toStartOf="@id/dashboard" app:srcCompat="@drawable/scroll_image" /> </androidx.constraintlayout.motion.widget.MotionLayout>
第二步:修正MotionScene配置
调整后所有需要动效的控件都是MotionLayout的子View,配置的过渡和属性都会生效,可添加alpha过渡实现箭头自然消失的效果:
<?xml version="1.0" encoding="utf-8"?> <MotionScene xmlns:android="http://schemas.android.com/apk/res/android" xmlns:motion="http://schemas.android.com/apk/res-auto"> <Transition motion:constraintSetEnd="@+id/end" motion:constraintSetStart="@id/start" motion:duration="300"> <OnSwipe motion:touchAnchorId="@id/dashboard" motion:dragDirection="dragUp" motion:touchAnchorSide="top" /> <!-- 可选:添加关键帧实现滑动过程中箭头渐隐,效果更顺滑 --> <KeyFrameSet> <KeyAttribute motion:framePosition="50" motion:target="@id/swipeUpPic"> <CustomAttribute motion:attributeName="alpha" motion:customFloatValue="0.5" /> </KeyAttribute> </KeyFrameSet> </Transition> <ConstraintSet android:id="@+id/start"> <Constraint android:id="@id/dashboard" android:layout_width="match_parent" android:layout_height="500dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintEnd_toEndOf="parent" motion:layout_constraintStart_toStartOf="parent" > </Constraint> <Constraint android:id="@id/swipeUpPic" android:layout_width="match_parent" android:layout_height="100dp" android:alpha="1" android:visibility="visible" motion:layout_constraintBottom_toBottomOf="@id/dashboard" motion:layout_constraintEnd_toEndOf="@id/dashboard" motion:layout_constraintStart_toStartOf="@id/dashboard" > </Constraint> </ConstraintSet> <ConstraintSet android:id="@+id/end"> <Constraint android:id="@id/dashboard" android:layout_width="match_parent" android:layout_height="400dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintEnd_toEndOf="parent" motion:layout_constraintStart_toStartOf="parent" > </Constraint> <Constraint android:id="@id/swipeUpPic" android:layout_width="match_parent" android:layout_height="100dp" android:alpha="0" android:visibility="invisible" motion:layout_constraintBottom_toBottomOf="@id/dashboard" motion:layout_constraintEnd_toEndOf="@id/dashboard" motion:layout_constraintStart_toStartOf="@id/dashboard" > </Constraint> </ConstraintSet> </MotionScene>
可选:代码自定义逻辑
如果需要添加额外业务逻辑,不要给dashboard设置触摸监听器,直接给MotionLayout设置TransitionListener即可,不会拦截原有滑动事件:
motionLayout.setTransitionListener(object : MotionLayout.TransitionListener { override fun onTransitionStarted(motionLayout: MotionLayout?, startId: Int, endId: Int) {} override fun onTransitionChange(motionLayout: MotionLayout?, startId: Int, endId: Int, progress: Float) { // 可根据滑动进度自定义箭头显示逻辑,例:swipeUpPic.alpha = 1 - progress } override fun onTransitionCompleted(motionLayout: MotionLayout?, currentId: Int) { // 上滑完成后隐藏箭头 swipeUpPic.visibility = if (currentId == R.id.end) View.GONE else View.VISIBLE } override fun onTransitionTrigger(motionLayout: MotionLayout?, triggerId: Int, positive: Boolean, progress: Float) {} })
内容的提问来源于stack exchange,提问作者Buddy
相关产品推荐
相关产品推荐

