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

如何实现Fragment与子Fragment及跨层级Fragment的共享元素过渡

共享元素过渡失效问题及跨层级过渡实现方案

问题背景

现有Splash Fragment、带底部导航和bottom_nav_graph的Main Fragment,需实现两个需求:

  • Splash到Main默认子Fragment(Home Fragment)的共享元素过渡(过渡元素仅存在于Splash和Home中)
  • Home Fragment到与Main同层级的UserDetail Fragment的类似共享元素过渡

当前Splash到Home的过渡未生效,相关代码如下:

SplashFragment 布局代码

<com.airbnb.lottie.LottieAnimationView
    android:id="@+id/lottie_loading"
    android:layout_width="192dp"
    android:layout_height="wrap_content"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:lottie_autoPlay="true"
    android:transitionName="@string/splash_lottie"
    app:lottie_fileName="splash.json" />

SplashFragment 逻辑代码

val sharedElement = binding.lottieLoading
val extras = FragmentNavigatorExtras(sharedElement to sharedElement.transitionName)
findNavController().navigateSafe(R.id.mainContainerFragment, navExtras = extras)

MainFragment 尝试过的代码

要么无额外代码,要么:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    sharedElementEnterTransition = TransitionInflater.from(context).inflateTransition(android.R.transition.move)
}

HomeFragment 布局代码

<androidx.appcompat.widget.AppCompatImageView
    android:id="@+id/iv_top_logo"
    android:layout_width="110dp"
    android:layout_height="33dp"
    android:layout_marginTop="40dp"
    android:scaleType="centerCrop"
    android:scaleX="1.4"
    android:scaleY="1.4"
    android:transitionName="@string/splash_lottie"
    app:layout_constraintStart_toStartOf="@id/actv_top_label_title"
    app:layout_constraintTop_toTopOf="parent"
    app:srcCompat="@drawable/logo_white"
    app:tint="@color/primary" />

HomeFragment 尝试过的逻辑代码

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    sharedElementEnterTransition = TransitionInflater.from(context).inflateTransition(android.R.transition.move)
}

我认为不同View类型(LottieAnimationView与ImageView)不影响过渡,transitionName是关键,但当前过渡未生效,请问遗漏了什么?另外,Home到同层级UserDetail的过渡该怎么实现?


问题1:Splash到Home共享元素过渡失效的修复

核心遗漏点

从Splash跳转到MainFragment时,共享元素参数默认只会传递给目标Fragment(Main),不会自动转发给它的子Fragment(Home),导致Home无法接收到过渡信号。

修复步骤

  1. MainFragment转发共享元素参数
    在MainFragment中获取Splash传来的过渡参数,加载HomeFragment时传递给它:

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // 获取从Splash传递的共享元素参数
        val navExtras = arguments?.getParcelable<FragmentNavigatorExtras>(NavController.KEY_NAV_EXTRAS)
        navExtras?.let { extras ->
            val (sharedView, transitionName) = extras.sharedElements.entries.first()
            // 加载HomeFragment并传递共享元素
            childFragmentManager.beginTransaction()
                .setReorderingAllowed(true)
                .addSharedElement(sharedView, transitionName)
                .replace(R.id.bottom_nav_container, HomeFragment())
                .commit()
        }
    }
    
  2. 禁用MainFragment的过渡动画
    Main作为中间容器不需要过渡,避免干扰Splash到Home的动画:

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enterTransition = null
        exitTransition = null
        sharedElementEnterTransition = null
        sharedElementExitTransition = null
    }
    
  3. 确保HomeFragment过渡时机正确
    延迟过渡直到目标View加载完成,避免因View未初始化导致过渡失效:

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        postponeEnterTransition()
        binding.ivTopLogo.doOnPreDraw {
            startPostponedEnterTransition()
        }
    }
    

问题2:Home到同层级UserDetail Fragment的过渡实现

由于Home和UserDetail同属Main的子Fragment,可直接通过子导航控制器传递共享元素参数:

实现步骤

  1. 给UserDetailFragment的过渡View设置相同transitionName

    <ImageView
        android:id="@+id/user_logo"
        android:transitionName="@string/splash_lottie"
        <!-- 其他布局属性 -->
        />
    
  2. HomeFragment中触发跳转并传递参数

    val sharedView = binding.ivTopLogo
    val extras = FragmentNavigatorExtras(sharedView to sharedView.transitionName)
    findNavController().navigate(R.id.action_home_to_userDetail, null, null, extras)
    
  3. 配置UserDetailFragment的过渡

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        sharedElementEnterTransition = TransitionInflater.from(context).inflateTransition(android.R.transition.move)
    }
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        postponeEnterTransition()
        binding.userLogo.doOnPreDraw {
            startPostponedEnterTransition()
        }
    }
    

内容的提问来源于stack exchange,提问作者c-an

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 12:38:10