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

Fragment中结合AsyncLayoutInflater与SharedElementTransition实现遇阻求助

问题分析与解决方案

你的代码无法正常工作主要有几个核心问题,咱们一步步拆解:

1. AsyncLayoutInflater的回调运行在后台线程

AsyncLayoutInflater的核心是在后台线程完成布局inflation,但你在回调里直接执行了addView、设置transitionName这些UI操作——Android要求所有UI操作必须在主线程执行,这不仅会导致线程安全问题,还会让共享元素过渡系统无法正确识别目标视图(因为视图是在后台线程被添加的,主线程的视图树还没同步)。

2. 启动过渡的时机过早

startPostponedEnterTransition()被直接放在回调里,但此时视图可能还没被完全附加到视图树、没完成测量/layout,过渡系统找不到有效的共享元素,自然无法触发过渡动画。

修正后的代码实现

下面是修复后的完整逻辑,我会标注关键改动点:

// 首先,在Fragment的onCreateView里先推迟过渡
override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    // 必须先调用这个,告诉系统等待我们准备好再启动过渡
    postponeEnterTransition()
    // 创建AsyncLayoutInflater实例
    val asyncLayoutInflater = AsyncLayoutInflater(requireContext())
    // 这里用FrameLayout作为根容器,也可以复用你原本的view参数
    val rootView = FrameLayout(requireContext())
    
    asyncLayoutInflater.inflate(R.layout.fragment, rootView) { inflatedView, _, _ ->
        // 1. 所有UI操作切换到主线程执行
        requireActivity().runOnUiThread {
            val binding = FragmentBinding.bind(inflatedView)
            binding.viewModel = viewModel
            
            // 确保视图只被添加一次,避免重复添加的异常
            if (inflatedView.parent == null) {
                rootView.addView(inflatedView)
            }
            
            // 2. 给共享元素设置transitionName
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                binding.myImageView.transitionName = entity.name
            }
            
            // 3. 监听视图绘制完成,确保共享元素已准备好再启动过渡
            binding.myImageView.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
                override fun onPreDraw(): Boolean {
                    binding.myImageView.viewTreeObserver.removeOnPreDrawListener(this)
                    // 现在可以安全启动过渡了
                    startPostponedEnterTransition()
                    displayInfo()
                    return true
                }
            })
        }
    }
    return rootView
}

额外注意事项

  • 确保启动过渡的当前Fragment和发起过渡的源Fragment都正确配置了共享元素:源Fragment的ImageView也要设置相同的transitionName,并且在跳转时通过FragmentNavigatorExtras传递共享元素信息。
  • 如果你的view参数是来自onCreateView的container,注意先判断inflatedView.parent == null再执行addView,避免视图重复添加的崩溃。
  • AsyncLayoutInflater只负责后台inflation操作,所有后续的视图绑定、添加到视图树、过渡配置等逻辑,都必须回到主线程执行。

内容的提问来源于stack exchange,提问作者Ruslan Leshchenko

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 04:05:51