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

SwiftUI中基于Item实现多Sheet层级叠加的解决方案

解决方案:用栈管理Sheet实现叠加效果

核心思路是把原来的单个currentSheet变量改成栈结构,用来记录所有打开的Sheet层级。这样每次打开新Sheet时只是往栈里添加元素,关闭时移除最后一个元素,就能实现Sheet叠加的效果,无需定义多个isPresented或多份Sheet实例。

修改后的完整代码

enum SheetActions: Identifiable {
    case firstSheet, secondSheet

    var id: Int {
        switch self {
        case .firstSheet:
            return 1
        case .secondSheet:
            return 2
        }
    }
}

struct ContentView: View {
    // 用栈存储Sheet的打开状态,替代单个可选值
    @State private var sheetStack: [SheetActions] = []
    
    // 自定义绑定,给sheet(item:)提供当前显示的Sheet(栈顶元素)
    private var currentSheetBinding: Binding<SheetActions?> {
        Binding(
            get: { sheetStack.last },
            set: { newValue in
                if let newValue {
                    // 新Sheet入栈
                    sheetStack.append(newValue)
                } else {
                    // 关闭时出栈
                    if !sheetStack.isEmpty {
                        sheetStack.removeLast()
                    }
                }
            }
        )
    }

    var body: some View {
        VStack {
            Button("Open First Sheet") {
                sheetStack.append(.firstSheet)
            }
            .padding()
        }
        .sheet(item: currentSheetBinding) { item in
            switch item {
            case .firstSheet:
                FirstSheetView(sheetStack: $sheetStack)
            case .secondSheet:
                Text("Second Sheet")
                    .navigationBarTitle("Second Sheet", displayMode: .inline)
                    .navigationBarItems(trailing: Button("Close") {
                        sheetStack.removeLast()
                    })
            }
        }
    }
}

struct FirstSheetView: View {
    @Binding var sheetStack: [SheetActions]

    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(destination: SecondView(sheetStack: $sheetStack)) {
                    Text("Navigate to Second View")
                }
                .padding()
            }
            .navigationBarTitle("First Sheet", displayMode: .inline)
            .navigationBarItems(trailing: Button(action: {
                sheetStack.removeLast()
            }) {
                Text("Close")
            })
        }
    }
}

struct SecondView: View {
    @Binding var sheetStack: [SheetActions]

    var body: some View {
        VStack {
            Button("Open Second Sheet") {
                // 打开新Sheet时,往栈里添加元素,而非替换
                sheetStack.append(.secondSheet)
            }
            .padding()
        }
        .navigationBarTitle("Second View", displayMode: .inline)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

关键改动说明

  • 栈结构替代单个变量:用[SheetActions]类型的sheetStack存储所有打开的Sheet,栈顶元素就是当前显示的Sheet。
  • 自定义Binding:通过currentSheetBinding把栈的操作和sheet(item:)的要求对接,当Sheet被系统自动dismiss(比如向下滑动)时,也能正确触发栈的出栈操作。
  • 打开/关闭逻辑调整:打开新Sheet时调用sheetStack.append(_:),关闭时调用sheetStack.removeLast(),完美实现层级叠加和逐级关闭。
  • 视图传参调整:把原来的currentSheet绑定换成sheetStack绑定,让子视图也能操作栈结构。

这样修改后,点击「Open Second Sheet」时,新Sheet会直接叠加在当前Sheet之上,关闭时会从最上层开始逐级关闭,完全符合你的需求,且不需要额外定义多个Sheet实例或isPresented变量。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 16:27:47