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

GridLayout内CardView的Shared Element Transition无法生效问题排查

问题分析与修复方案

核心问题

你的共享元素过渡失效是以下几个关键错误导致:

1. 共享元素TransitionName不匹配

源CardView设置的TransitionName是it.id.toString()(比如first、second),但目标CardView设置的是固定值scale_transition,系统无法识别这是同一组共享元素,自然不会触发过渡动画。

2. 过渡资源加载错误

GameSelectionFragment中加载过渡文件时多了.xml后缀,导致资源找不到:

// 错误写法
inflateTransition(R.transition.scale_transition.xml)
// 正确写法
inflateTransition(R.transition.scale_transition)

3. 不必要的过渡延迟

你的目标CardView没有异步加载内容(比如图片),不需要调用postponeEnterTransition,过早触发startPostponedEnterTransition反而可能导致过渡异常。


修复后的代码示例

修改AppsFragment.kt

确保源CardView和目标CardView使用相同的TransitionName,通过Bundle将名称传递给目标Fragment:

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    binding = FragmentAppsBinding.inflate(layoutInflater)
    val view = binding.root

    binding.appsGridLayout.forEach { cardView ->
        val transitionName = cardView.id.toString()
        ViewCompat.setTransitionName(cardView as CardView, transitionName)
        cardView.setOnClickListener {
            parentFragmentManager.commit {
                val newFragment = GameSelectionFragment().apply {
                    arguments = Bundle().apply {
                        putString("TRANSITION_NAME", transitionName)
                    }
                }
                setReorderingAllowed(true)
                addSharedElement(cardView, transitionName)
                replace(R.id.appFragment, newFragment)
                addToBackStack(null)
            }
        }
    }
    return view
}

修改GameSelectionFragment.kt

修正过渡资源加载,接收传递的TransitionName并设置给目标CardView:

class GameSelectionFragment : Fragment() {
    private lateinit var binding: FragmentGameSelectionBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 修正资源加载路径
        sharedElementEnterTransition = TransitionInflater.from(requireContext())
            .inflateTransition(R.transition.scale_transition)
        // 设置返回过渡,保证返回时的动画一致性
        sharedElementReturnTransition = TransitionInflater.from(requireContext())
            .inflateTransition(R.transition.scale_transition)
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentGameSelectionBinding.inflate(layoutInflater)
        val view = binding.root
        // 获取传递的TransitionName并设置
        arguments?.getString("TRANSITION_NAME")?.let {
            ViewCompat.setTransitionName(binding.appCard, it)
        }
        return view
    }
}

scale_transition.xml(无需修改)

你的过渡配置是正确的:

<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android" android:duration="300">
    <changeBounds/>
    <changeTransform/>
</transitionSet>

额外注意事项

  • 确保Activity主题开启窗口内容过渡,在styles.xml中添加:
    <item name="android:windowContentTransitions">true</item>
    
  • 移除布局中android:animateLayoutChanges="true"属性,该属性可能和共享元素过渡冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 22:45:15