You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android ConstraintLayout Slide Transition动画异常求助:视图提前显示完整高度及关联组件无过渡动画

解决ConstraintLayout Slide Transition动画异常问题

嘿,我帮你分析下你遇到的这几个动画问题,然后给出可行的解决方案!

问题根源分析

你的问题主要出在直接切换View的VISIBLE/GONE状态上:

  1. 当你把bottomBlue设为GONE时,ConstraintLayout会瞬间移除这个View的布局占位,导致依赖它的topRed(以及按钮)瞬间填充剩余空间,所以按钮没有平滑过渡;
  2. 显示时同理,bottomBlue的占位瞬间出现,topRed瞬间收缩,按钮直接上移;
  3. 白色区域是因为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 10:37:42