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

能否为单个视图设置两种.navigationTransition导航转场效果?

实现NavigationStack中两种场景的不同转场效果

你遇到的问题是因为直接给详情视图叠加两个navigationTransition,系统只会应用最后一个,且无法区分跳转的触发来源。要实现两种场景的不同转场,需要通过区分跳转的触发类型来针对性设置转场效果,具体修改方案如下:

关键修改点

  • 定义枚举区分跳转场景(添加/查看),让路径能携带触发类型信息
  • 根据不同的跳转场景,给详情视图应用对应的转场动画
  • 确保matchedTransitionSource的ID与navigationTransition的sourceID精准匹配

修改后的完整代码

import SwiftUI

// 定义枚举区分跳转类型,携带Item和触发来源
enum NavigationAction: Hashable {
    case add(Item)
    case read(Item)
}

struct ContentView: View {
    @State private var items: [Item] = []
    @State private var path: [NavigationAction] = []
    @Namespace private var namespace
    
    var body: some View {
        NavigationStack(path: $path) {
            List {
                ForEach(items) { item in
                    NavigationLink(value: NavigationAction.read(item)) {
                        Text(item.content)
                            .matchedTransitionSource(id: "read-\(item.id.uuidString)", in: namespace)
                    }
                }
            }
            .navigationDestination(for: NavigationAction.self) { action in
                switch action {
                case .add(let item):
                    ItemEditingView(item: item)
                        .navigationTransition(.zoom(sourceID: "add", in: namespace))
                case .read(let item):
                    ItemEditingView(item: item)
                        .navigationTransition(.zoom(sourceID: "read-\(item.id.uuidString)", in: namespace))
                }
            }
            .toolbar {
                ToolbarItem {
                    Button(action: addItem) {
                        Label("Add Item", systemImage: "plus")
                            .matchedTransitionSource(id: "add", in: namespace)
                    }
                }
            }
        }
    }
    
    private func addItem() {
        let newItem = Item(content: "New Item \(items.count + 1)")
        items.append(newItem)
        path.append(.add(newItem))
    }
}

// 假设的Item和ItemEditingView定义
struct Item: Identifiable, Hashable {
    let id = UUID()
    var content: String
}

struct ItemEditingView: View {
    let item: Item
    
    var body: some View {
        Text("Editing: \(item.content)")
            .font(.title)
            .navigationTitle("Edit Item")
    }
}

代码说明

  1. 枚举NavigationAction:通过.add和.read两个case区分跳转来源,同时携带对应的Item数据,让跳转时能明确触发场景。
  2. 路径类型修改:把path的类型从[Item]改为[NavigationAction],让路径能传递触发类型信息。
  3. 转场匹配:在navigationDestination中根据枚举case选择对应的转场动画,确保点击+按钮时用sourceID: "add"的转场,点击列表项时用对应item的唯一ID转场。
  4. 按钮跳转逻辑:点击+按钮时,先创建新Item并加入列表,再把.add(newItem)加入路径触发跳转,此时转场会和按钮的matchedTransitionSource匹配。

这样修改后,两种场景的转场效果就能分别正常生效了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 14:25:03