使用TransitionManager.go()切换场景时ChangeBounds收缩动画失效
问题:TransitionManager收缩动画不生效,仅展开动画正常
需求说明
- 点击「折叠」按钮(button1):将容器中的view1替换为view2,实现展开动画
- 点击「展开」按钮(button2):将容器中的view2替换为view1,实现收缩动画
问题描述
采用TransitionManager.go()结合ChangeBounds()实现视图切换动画,但仅展开动画能正常执行,点击收缩按钮时无动画效果,视图直接切换。
相关代码
Main Activity 代码
private val expandTransition: Transition = TransitionSet().addTransition(ChangeBounds()).setDuration(500) private val shrinkTransition: Transition = TransitionSet().addTransition(ChangeBounds()).setDuration(500) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main_1) view2Layout = LayoutInflater.from(this).inflate(R.layout.sceneB, null, false) view2 = view2Layout.findViewById<ViewGroup>(R.id.view2) view1 = findViewById(R.id.view1) val sceneA = Scene(container, view2) val sceneB = Scene(container, view1) (view2.parent as? ViewGroup)?.removeView(view2) button1.setOnClickListener { TransitionManager.go(sceneA, expandTransition) } button2.setOnClickListener { TransitionManager.go(sceneB, shrinkTransition) } }
activity_main_1.xml 代码
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <FrameLayout android:id="@+id/container" android:layout_width="wrap_content" android:layout_height="100dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent"> <View android:id="@+id/view1" android:layout_width="40dp" android:layout_height="100dp" android:background="#fff000" /> </FrameLayout> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="50dp" android:text="click for fold" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@id/button2" /> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="50dp" android:text="click for expand" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
sceneB.xml 代码
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="88dp" android:layout_height="100dp"> <FrameLayout android:id="@+id/view2" android:background="@color/design_default_color_secondary_variant" android:layout_width="88dp" android:layout_height="match_parent"/> </FrameLayout>
问题原因与解决方案
核心问题
Scene逻辑颠倒+状态追踪失效:
- 你把
sceneA(绑定view2)和sceneB(绑定view1)的触发按钮搞反了,逻辑完全错误。 - 使用
Scene(container, view)构造方法时,手动移除view2的操作导致后续切换回view1时,view1已被之前的Scene操作从容器中移除,TransitionManager无法获取前后视图状态对比,动画无法触发。
- 你把
容器布局限制:container的
layout_width设为wrap_content,切换回view1时容器宽度瞬间收缩,没有过渡空间。
修正方案
改用TransitionManager.beginDelayedTransition()配合手动替换视图的方式,更直观且能正确追踪状态变化:
修正后的Main Activity代码
private val expandTransition: Transition = TransitionSet().addTransition(ChangeBounds()).setDuration(500) private val shrinkTransition: Transition = TransitionSet().addTransition(ChangeBounds()).setDuration(500) private lateinit var view2: ViewGroup private lateinit var container: FrameLayout private lateinit var view1: View override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main_1) container = findViewById(R.id.container) view1 = findViewById(R.id.view1) // 直接加载view2,去掉多余的父布局 view2 = LayoutInflater.from(this).inflate(R.layout.view2, container, false) as ViewGroup findViewById<Button>(R.id.button).setOnClickListener { // 折叠:切换为view1,执行收缩动画 TransitionManager.beginDelayedTransition(container, shrinkTransition) container.removeAllViews() container.addView(view1) } findViewById<Button>(R.id.button2).setOnClickListener { // 展开:切换为view2,执行展开动画 TransitionManager.beginDelayedTransition(container, expandTransition) container.removeAllViews() container.addView(view2) } }
新增view2.xml(替代原sceneB.xml)
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/view2" android:background="@color/design_default_color_secondary_variant" android:layout_width="88dp" android:layout_height="match_parent"/>
调整container布局(可选)
将container的layout_width改为match_parent,避免容器宽度瞬间变化影响动画:
<FrameLayout android:id="@+id/container" android:layout_width="match_parent" android:layout_height="100dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent">
原理说明
TransitionManager.beginDelayedTransition()会在修改视图结构前记录当前状态,修改完成后自动对比前后状态并触发过渡动画,无需手动创建Scene,能有效避免状态追踪失效问题。
内容的提问来源于stack exchange,提问作者yogurt
相关产品推荐
相关产品推荐

