Android开发:如何延迟View隐藏至动画执行完成?TransitionManager动画异常问题排查
解决TransitionManager隐藏View时立即消失的问题
这个问题的核心原因是:当你直接将View设置为View.GONE时,该View会立即从布局树中被移除,TransitionManager还没来得及捕捉它的状态变化来执行消失动画,就只能看到其他布局的位置调整动画,而目标View已经不见了。
下面提供两种可行的解决方案:
方案1:使用AutoTransition(最简单)
AutoTransition是Android提供的默认过渡动画组合,它包含了Fade(淡入淡出)和ChangeBounds(布局位置/尺寸变化)动画。使用它可以自动处理View显示/隐藏时的淡入淡出效果,同时配合布局调整动画,避免View立即消失。
修改你的点击事件代码如下:
binding.btn.setOnClickListener { // 替换ChangeBounds为AutoTransition val transition = AutoTransition() transition.addTarget(binding.ly1) transition.addTarget(binding.ly2) // 可选:设置动画时长,让效果更明显 transition.duration = 300 TransitionManager.beginDelayedTransition(binding.root, transition) binding.ly1.visibility = if (binding.ly1.isVisible) View.GONE else View.VISIBLE }
这样修改后,隐藏ly1时,它会先执行淡出动画,同时ly2平滑上移,动画完成后ly1才会被设置为GONE,完全符合你的需求。
方案2:手动控制View高度+监听动画结束(自定义性更强)
如果你想更精准地控制动画过程(比如只做高度收缩动画,不需要淡入淡出),可以先通过修改View的高度触发ChangeBounds动画,等动画结束后再将View设置为GONE。
步骤说明:
- 显示View时:恢复其固定高度并设置为VISIBLE
- 隐藏View时:先将高度改为0触发动画,动画结束后再设置为GONE
修改后的完整代码:
class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding // 保存ly1的原始高度(35dp) private val ly1OriginalHeightDp = 35 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) binding.btn.setOnClickListener { val transition = ChangeBounds() transition.addTarget(binding.ly1) transition.addTarget(binding.ly2) transition.duration = 300 if (binding.ly1.isVisible) { // 隐藏流程:先添加动画结束监听 transition.addListener(object : Transition.TransitionListener { override fun onTransitionStart(transition: Transition) {} override fun onTransitionEnd(transition: Transition) { // 动画完成后,将ly1设置为GONE binding.ly1.visibility = View.GONE // 移除监听,避免重复触发 transition.removeListener(this) } override fun onTransitionCancel(transition: Transition) { transition.removeListener(this) } override fun onTransitionPause(transition: Transition) {} override fun onTransitionResume(transition: Transition) {} }) TransitionManager.beginDelayedTransition(binding.root, transition) // 修改ly1的高度为0,触发收缩动画 val params = binding.ly1.layoutParams as ConstraintLayout.LayoutParams params.height = 0 binding.ly1.layoutParams = params } else { // 显示流程:恢复高度并设置为VISIBLE TransitionManager.beginDelayedTransition(binding.root, transition) binding.ly1.visibility = View.VISIBLE val params = binding.ly1.layoutParams as ConstraintLayout.LayoutParams params.height = ly1OriginalHeightDp.dpToPx(this) binding.ly1.layoutParams = params } } } } // 扩展函数:dp转px fun Int.dpToPx(context: Context): Int { return (this * context.resources.displayMetrics.density).toInt() }
这种方式可以让ly1以高度收缩的动画逐渐消失,同时ly2平滑上移,动画结束后ly1才会被彻底隐藏(从布局树移除)。
内容的提问来源于stack exchange,提问作者dybm27




