如何在MotionLayout过渡期间平滑更改View的圆角半径?
解决MotionLayout过渡中修改Drawable圆角半径的问题
你提到的问题确实存在:MotionLayout的XML配置里,默认CustomAttribute仅支持颜色Drawable的切换,无法直接对ShapeDrawable的圆角半径做平滑过渡。以下是几种可行的解决方式:
方法一:监听过渡进度动态修改圆角
给MotionLayout添加过渡监听,在过渡过程中实时计算并更新目标View背景的圆角半径:
motionLayout.setTransitionListener(object : MotionLayout.TransitionListener { override fun onTransitionStarted(p0: MotionLayout?, p1: Int, p2: Int) {} override fun onTransitionChange(motionLayout: MotionLayout?, startId: Int, endId: Int, progress: Float) { // 定义初始和目标圆角尺寸(需在dimens.xml中配置) val startRadius = resources.getDimension(R.dimen.start_corner_radius) val endRadius = resources.getDimension(R.dimen.end_corner_radius) // 根据过渡进度计算当前圆角值 val currentRadius = startRadius + (endRadius - startRadius) * progress // 修改背景Drawable的圆角 val bgDrawable = layout_player.background as GradientDrawable bgDrawable.cornerRadius = currentRadius layout_player.background = bgDrawable } override fun onTransitionCompleted(p0: MotionLayout?, p1: Int) {} override fun onTransitionTrigger(p0: MotionLayout?, p1: Int, p2: Boolean, p3: Float) {} })
注意:确保目标View的初始背景是GradientDrawable(XML中定义的shape默认就是这个类型),否则需要做类型兼容处理。
方法二:自定义可动画圆角的Drawable
通过自定义Drawable暴露圆角属性,让MotionLayout可以直接通过CustomAttribute过渡该属性:
- 自定义Drawable类:
class AnimatedCornerDrawable : GradientDrawable() { var cornerRadiusValue: Float get() = cornerRadius set(value) { cornerRadius = value invalidateSelf() } }
- 在布局中设置该Drawable为目标View的背景:
<androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/layout_player" android:background="@drawable/animated_corner_drawable" ...>
- 在MotionLayout的ConstraintSet中配置过渡属性:
<ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/layout_player" ...> <CustomAttribute motion:attributeName="cornerRadiusValue" motion:customFloatValue="@dimen/start_corner_radius" /> </Constraint> </ConstraintSet> <ConstraintSet android:id="@+id/end"> <Constraint android:id="@+id/layout_player" ...> <CustomAttribute motion:attributeName="cornerRadiusValue" motion:customFloatValue="@dimen/end_corner_radius" /> </Constraint> </ConstraintSet>
这种方式可以实现完全平滑的圆角过渡,且无需额外的代码监听。
方法三:直接切换不同圆角的Drawable(无平滑过渡)
如果不需要平滑过渡,仅需在过渡前后切换背景Drawable,可使用customDrawableValue属性替代customColorDrawableValue:
<ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/layout_player" ...> <CustomAttribute motion:attributeName="background" motion:customDrawableValue="@drawable/bg_player_control_part" /> </Constraint> </ConstraintSet> <ConstraintSet android:id="@+id/end"> <Constraint android:id="@+id/layout_player" ...> <CustomAttribute motion:attributeName="background" motion:customDrawableValue="@drawable/bg_player_control_part_round" /> </Constraint> </ConstraintSet>
此方式是直接替换Drawable,没有渐变效果,适合对过渡平滑度要求不高的场景。
内容的提问来源于stack exchange,提问作者Isuru Gunasekara
相关产品推荐
相关产品推荐

