MotionLayout搭配BottomSheet动画效果不符合预期如何解决
问题根源
你的方案存在事件冲突:BottomSheet的滑动事件由BottomSheetBehavior独立消费处理,MotionLayout自带的<OnSwipe>配置无法拦截到这部分滑动事件,因此无法驱动联动动画。同时你当前的MotionScene未明确声明起始状态的控件约束,也会导致动画行为异常。
修复步骤
步骤1:修改MotionScene配置
移除原有<OnSwipe>配置,补充明确的起始状态约束,同时修正头像的结束位置约束(匹配动效中缩小后靠左的效果):
<?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"> <Transition app:constraintSetEnd="@+id/end" app:constraintSetStart="@id/start" app:duration="1000"> <KeyFrameSet /> </Transition> <!-- 明确声明起始状态 --> <ConstraintSet android:id="@+id/start"> <Constraint android:id="@id/imageViewAvatar" android:layout_width="140dp" android:layout_height="140dp" android:layout_marginTop="16dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </ConstraintSet> <ConstraintSet android:id="@+id/end"> <Constraint android:id="@id/imageViewAvatar" android:layout_width="40dp" android:layout_height="40dp" android:layout_marginStart="16dp" android:layout_marginTop="16dp" <!-- 结束状态靠左,不需要居中 --> app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </ConstraintSet> </MotionScene>
步骤2:修正布局文件的小问题
首先给根MotionLayout添加id,再将CoordinatorLayout的高度改为match_parent,保证BottomSheet可以正常全屏展开:
<!-- 根MotionLayout加id --> <androidx.constraintlayout.motion.widget.MotionLayout android:id="@+id/motionLayout" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" app:layoutDescription="@xml/activity_main_scene" tools:context=".MainActivity"> <!-- 其他代码不变,修改CoordinatorLayout高度 --> <androidx.coordinatorlayout.widget.CoordinatorLayout android:id="@+id/coordinatorLayout2" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toTopOf="parent">
步骤3:在业务代码中关联BottomSheet滑动和MotionLayout进度
在Activity/Fragment中获取BottomSheetBehavior实例,添加滑动监听,将BottomSheet的偏移量同步为MotionLayout的动画进度:
// Kotlin 示例代码 val motionLayout = findViewById<MotionLayout>(R.id.motionLayout) val bottomSheet = findViewById<LinearLayoutCompat>(R.id.bottomSheet) val bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet) bottomSheetBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { override fun onStateChanged(bottomSheet: View, newState: Int) {} override fun onSlide(bottomSheet: View, slideOffset: Float) { // slideOffset范围:0为peek状态,1为完全展开,直接映射到MotionLayout的0-1进度 motionLayout.progress = slideOffset.coerceAtLeast(0f) } })
// Java 示例代码 MotionLayout motionLayout = findViewById(R.id.motionLayout); LinearLayoutCompat bottomSheet = findViewById(R.id.bottomSheet); BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet); bottomSheetBehavior.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) {} @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { motionLayout.setProgress(Math.max(slideOffset, 0f)); } });
额外说明
如果需要让BottomSheet的滑动和MotionLayout动画的时长完全匹配,可以调整MotionScene中Transition的duration参数和BottomSheet的fling速度参数对齐,一般默认配置就可以满足流畅联动的需求。
内容的提问来源于stack exchange,提问作者Sattar
相关产品推荐
相关产品推荐

