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

Compose实现的Fragment结合Fragment Navigation能否实现共享元素转场?

在Fragment Navigation下实现Compose Fragment间的共享元素转场

这种场景完全可行,核心是将Compose元素与Fragment Navigation的共享元素机制绑定,通过Compose的Modifier.sharedElement和Fragment转场API配合实现。以下是具体实现步骤和示例:

1. 配置Navigation转场基础

确保Navigation组件版本在2.4.0+,在导航图nav_graph.xml中为跳转动作配置共享元素转场:

<fragment
    android:id="@+id/fragmentA"
    android:name="com.example.FragmentA">
    <action
        android:id="@+id/action_fragmentA_to_bottomSheetFragmentB"
        app:destination="@id/bottomSheetFragmentB"
        app:sharedElementsEnterTransition="@transition/change_bounds"
        app:sharedElementsReturnTransition="@transition/change_bounds"/>
</fragment>
<fragment
    android:id="@+id/bottomSheetFragmentB"
    android:name="com.example.BottomSheetFragmentB"/>

2. 在Compose布局标记共享元素

两个Fragment的Compose内容中,用相同的唯一key标记需要共享的元素:

FragmentA的Compose内容

@Composable
fun FragmentAContent(onNavigate: (String) -> Unit) {
    val sharedKey = "shared_avatar"
    Box(modifier = Modifier.fillMaxSize()) {
        Image(
            painter = painterResource(R.drawable.avatar),
            contentDescription = "Avatar",
            modifier = Modifier
                .size(80.dp)
                .sharedElement(key = sharedKey, rememberSharedElementState())
                .clickable { onNavigate(sharedKey) }
        )
    }
}

BottomSheetFragmentB的Compose内容

@Composable
fun BottomSheetContent(sharedKey: String) {
    Box(modifier = Modifier.fillMaxSize()) {
        Image(
            painter = painterResource(R.drawable.avatar),
            contentDescription = "Avatar",
            modifier = Modifier
                .size(160.dp)
                .align(Alignment.TopCenter)
                .sharedElement(key = sharedKey, rememberSharedElementState())
        )
    }
}

3. 在Fragment中绑定转场逻辑

FragmentA中启动导航并传递共享元素

class FragmentA : Fragment() {
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        return ComposeView(requireContext()).apply {
            setContent {
                FragmentAContent { sharedKey ->
                    // 获取Compose共享元素的Node
                    val sharedNode = LocalSharedElementRoot.current?.findNode(sharedKey)
                    sharedNode?.let {
                        // 构建Fragment共享元素映射
                        val extras = FragmentNavigatorExtras(it to sharedKey)
                        findNavController().navigate(
                            R.id.action_fragmentA_to_bottomSheetFragmentB,
                            null,
                            null,
                            extras
                        )
                    }
                }
            }
        }
    }
}

BottomSheetFragmentB中接收转场

class BottomSheetFragmentB : BottomSheetDialogFragment() {
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        // 启用共享元素转场
        sharedElementEnterTransition = TransitionInflater.from(requireContext())
            .inflateTransition(R.transition.change_bounds)
        // 解决BottomSheet遮挡转场元素的问题
        dialog?.window?.sharedElementsUseOverlay = false
        
        return ComposeView(requireContext()).apply {
            setContent {
                BottomSheetContent(sharedKey = "shared_avatar")
            }
        }
    }
}

关键注意事项

  • 共享元素的key必须在两个Fragment中完全一致,这是转场匹配的核心。
  • 若使用BottomSheetDialogFragment,必须设置sharedElementsUseOverlay = false,避免转场元素被弹窗遮挡。
  • 建议使用Navigation 2.5.0及以上版本,兼容性更稳定。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 08:58:18