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

使用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>

问题原因与解决方案

核心问题

  1. Scene逻辑颠倒+状态追踪失效:

    • 你把sceneA(绑定view2)和sceneB(绑定view1)的触发按钮搞反了,逻辑完全错误。
    • 使用Scene(container, view)构造方法时,手动移除view2的操作导致后续切换回view1时,view1已被之前的Scene操作从容器中移除,TransitionManager无法获取前后视图状态对比,动画无法触发。
  2. 容器布局限制: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 14:15:34