如何在MotionLayout过渡时实现YouTube式调光效果?含架构疑问
问题解答
1. 过渡实现思路是否合理?
这个思路完全可行,甚至是这类视频窗口过渡场景的标准方案之一:
- MotionLayout本身就是为复杂布局过渡、属性动画量身设计的,用来控制视频容器的尺寸、位置变化非常合适
- 主Activity用FrameLayout作为容器,既能承载视频Fragment,也方便后续叠加调光层这类需要覆盖在上方的视图,布局层级清晰
2. 如何实现YouTube式的渐变调光效果?
有两种简洁的实现方式,不用过度依赖Listener也能搞定:
方式一:直接用MotionScene控制调光层的透明度(推荐)
在你的MotionLayout布局里,加一个全屏的半透明View(黑色背景),默认设为alpha="0",然后在MotionScene的过渡定义中,给这个View添加透明度的关键帧:
- 布局文件示例:
<androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:motion="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- 视频容器 --> <FrameLayout android:id="@+id/video_container" android:layout_width="match_parent" android:layout_height="match_parent"/> <!-- 调光层 --> <View android:id="@+id/dimmer" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#80000000" android:alpha="0"/> </androidx.constraintlayout.motion.widget.MotionLayout>
- MotionScene文件示例(比如
res/xml/scene_video_transition.xml):
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android" xmlns:motion="http://schemas.android.com/apk/res-auto"> <Transition motion:constraintSetStart="@id/start" motion:constraintSetEnd="@id/end" motion:duration="300"> <!-- 视频容器的尺寸位置过渡 --> <KeyFrameSet> <PositionKeyFrame motion:target="@id/video_container" motion:framePosition="0" motion:motionX="0" motion:motionY="0"/> <PositionKeyFrame motion:target="@id/video_container" motion:framePosition="100" motion:motionX="20dp" motion:motionY="20dp"/> <SizeKeyFrame motion:target="@id/video_container" motion:framePosition="0" motion:widthPercent="1.0" motion:heightPercent="1.0"/> <SizeKeyFrame motion:target="@id/video_container" motion:framePosition="100" motion:widthPercent="0.3" motion:heightPercent="0.2"/> <!-- 调光层的透明度渐变 --> <AttributeKeyFrame motion:target="@id/dimmer" motion:framePosition="0" motion:attributeName="alpha" motion:customFloatValue="0"/> <AttributeKeyFrame motion:target="@id/dimmer" motion:framePosition="100" motion:attributeName="alpha" motion:customFloatValue="1"/> </KeyFrameSet> </Transition> <ConstraintSet android:id="@+id/start"> <!-- 初始状态约束,视频容器全屏 --> <Constraint android:id="@id/video_container" android:layout_width="match_parent" android:layout_height="match_parent"/> </ConstraintSet> <ConstraintSet android:id="@+id/end"> <!-- 结束状态约束,视频容器缩小到右下角 --> <Constraint android:id="@id/video_container" android:layout_width="0dp" android:layout_height="0dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintEnd_toEndOf="parent" motion:layout_constraintWidth_percent="0.3" motion:layout_constraintHeight_percent="0.2"/> </ConstraintSet> </MotionScene>
这样MotionLayout会自动在过渡过程中同步调整调光层的透明度,完全不用写Java/Kotlin代码。
方式二:用MotionLayout.TransitionListener动态控制
如果你更倾向用Listener,也可以在Fragment里监听过渡进度,动态设置调光层的alpha:
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) { // progress范围是0到1,对应过渡的起始到结束 dimmerView.alpha = progress } override fun onTransitionCompleted(motionLayout: MotionLayout, currentId: Int) {} override fun onTransitionTrigger(motionLayout: MotionLayout, triggerId: Int, positive: Boolean, progress: Float) {} })
这种方式适合需要在过渡过程中做额外逻辑的场景,比如同时调整其他视图的属性。
内容的提问来源于stack exchange,提问作者MathematicsBeginner
相关产品推荐
相关产品推荐

