Android ConstraintLayout Slide Transition动画异常求助:视图提前显示完整高度及关联组件无过渡动画
解决ConstraintLayout Slide Transition动画异常问题
嘿,我帮你分析下你遇到的这几个动画问题,然后给出可行的解决方案!
问题根源分析
你的问题主要出在直接切换View的VISIBLE/GONE状态上:
- 当你把
bottomBlue设为GONE时,ConstraintLayout会瞬间移除这个View的布局占位,导致依赖它的topRed(以及按钮)瞬间填充剩余空间,所以按钮没有平滑过渡; - 显示时同理,
bottomBlue的占位瞬间出现,topRed瞬间收缩,按钮直接上移; - 白色区域是因为
bottomBlue滑出动画还没结束,topRed已经占满了父布局,两者动画不同步导致的空白。
解决方案:用高度变化替代VISIBLE/GONE切换
我们不直接修改View的可见性,而是通过修改bottomBlue的高度来实现显示/隐藏,这样ConstraintLayout会自动处理依赖View的约束动画,同时配合Slide过渡实现平滑效果。
修改后的Activity代码
import android.os.Bundle import android.view.Gravity import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet import androidx.transition.Slide import androidx.transition.TransitionManager import com.tests.playground.R class ConstraintLayoutTransitionActivity : AppCompatActivity() { private val rootView: ConstraintLayout by lazy { findViewById(R.id.root) } private val bottomBlueView: View by lazy { findViewById(R.id.bottomBlue) } private val switchButton: View by lazy { findViewById(R.id.switchButton) } private var isBottomBlueViewShowing = true private val bottomBlueHeight = 142 // 原始高度,单位dp override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_constraint_layout_transition) switchButton.setOnClickListener(::onSwitchButtonClicked) } @Synchronized private fun onSwitchButtonClicked(view: View) { isBottomBlueViewShowing = !isBottomBlueViewShowing val constraintSet = ConstraintSet() constraintSet.clone(rootView) val transition = Slide(Gravity.BOTTOM) transition.duration = 1000L if (isBottomBlueViewShowing) { // 显示:设置为目标高度 constraintSet.constrainHeight(bottomBlueView.id, bottomBlueHeight.dpToPx(this)) transition.mode = Slide.MODE_IN } else { // 隐藏:设置高度为0 constraintSet.constrainHeight(bottomBlueView.id, 0) transition.mode = Slide.MODE_OUT } TransitionManager.beginDelayedTransition(rootView, transition) constraintSet.applyTo(rootView) } // 扩展函数:dp转px,确保高度适配不同屏幕 private fun Int.dpToPx(context: AppCompatActivity): Int { return (this * context.resources.displayMetrics.density).toInt() } }
为什么这样有效?
- 我们通过修改
bottomBlue的高度(从0到142dp,或反之),让它始终保留在布局结构中,ConstraintLayout会自动计算topRed的约束变化,并生成平滑的过渡动画,按钮也会跟着缓慢移动; - Slide过渡会作用于
bottomBlue的高度变化,实现从底部滑入/滑出的效果,和其他View的动画完全同步,不会出现空白区域。
另一种简化方案:使用AutoTransition
如果你不想手动处理Slide的mode,可以直接用AutoTransition,它会自动处理布局变化的所有动画(包括位置移动、大小变化、淡入淡出),代码更简洁:
把transition的创建代码替换成:
val transition = androidx.transition.AutoTransition() transition.duration = 1000L
这样不需要设置mode,AutoTransition会自动识别是显示还是隐藏操作,生成合适的动画效果。
注意事项
- 确保布局中
bottomBlue的初始高度是142dp(和代码中一致); - 不要使用
GONE,因为GONE会让View完全脱离布局,导致约束瞬间更新,无法生成平滑过渡。
内容的提问来源于stack exchange,提问作者Augusto Carmo
相关产品推荐
相关产品推荐

