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

如何在SwiftUI中通过一次动画关闭多个sheet?

在SwiftUI中同步关闭多个Sheet的解决方案

问题原因

你当前的代码中,直接依次设置showDetailSheet = false和showMainSheet = false时,SwiftUI会分别处理这两个状态变更,导致两个Sheet的关闭动画先后触发,无法同步执行。

解决方案1:用withAnimation包裹状态修改

直接在按钮动作中,将两个状态的修改包裹在withAnimation闭包内,强制SwiftUI同步执行状态变更对应的动画:

struct ContentView: View {
    @State var showMainSheet = false
    @State var showDetailSheet = false
    var body: some View {
        VStack {
            Button("Show Main Sheet") {
                showMainSheet = true
            }
        }
        .sheet(isPresented: $showMainSheet) {
            Button("Show Detail Sheet") {
                showDetailSheet = true
            }
            .presentationDetents([.medium])
            .fullScreenCover(isPresented: $showDetailSheet) {
                Button("Dismiss All") {
                    // 用withAnimation同步触发两个状态变更
                    withAnimation {
                        showDetailSheet = false
                        showMainSheet = false
                    }
                }
            }
        }
    }
}

解决方案2:使用环境DismissAction同步关闭

通过SwiftUI的环境@Environment(\.dismiss)获取每个Sheet的关闭动作,在统一的按钮事件中同步调用这些动作,配合withAnimation实现同步动画:

struct ContentView: View {
    @State var showMainSheet = false
    @State var showDetailSheet = false
    
    var body: some View {
        VStack {
            Button("Show Main Sheet") {
                showMainSheet = true
            }
        }
        .sheet(isPresented: $showMainSheet) {
            MainSheetView(showDetailSheet: $showDetailSheet)
        }
    }
}

// 主Sheet视图
struct MainSheetView: View {
    @Binding var showDetailSheet: Bool
    @Environment(\.dismiss) private var dismissMainSheet
    
    var body: some View {
        Button("Show Detail Sheet") {
            showDetailSheet = true
        }
        .presentationDetents([.medium])
        .fullScreenCover(isPresented: $showDetailSheet) {
            // 将主Sheet的关闭动作传递给子Sheet
            DetailSheetView(dismissMainSheet: dismissMainSheet)
        }
    }
}

// 详情Sheet视图
struct DetailSheetView: View {
    let dismissMainSheet: DismissAction
    @Environment(\.dismiss) private var dismissDetailSheet
    
    var body: some View {
        Button("Dismiss All") {
            withAnimation {
                // 同步调用两个Sheet的关闭动作
                dismissDetailSheet()
                dismissMainSheet()
            }
        }
    }
}

解决方案3:统一状态管理(推荐)

使用ObservableObject封装所有Sheet的显示状态,通过统一的方法触发同步关闭,代码结构更清晰,也便于后续扩展:

// 状态管理类
class SheetManager: ObservableObject {
    @Published var showMainSheet = false
    @Published var showDetailSheet = false
    
    // 同步关闭所有Sheet的方法
    func dismissAll() {
        withAnimation {
            showDetailSheet = false
            showMainSheet = false
        }
    }
}

struct ContentView: View {
    // 使用StateObject管理状态
    @StateObject private var sheetManager = SheetManager()
    
    var body: some View {
        VStack {
            Button("Show Main Sheet") {
                sheetManager.showMainSheet = true
            }
        }
        .sheet(isPresented: $sheetManager.showMainSheet) {
            Button("Show Detail Sheet") {
                sheetManager.showDetailSheet = true
            }
            .presentationDetents([.medium])
            .fullScreenCover(isPresented: $sheetManager.showDetailSheet) {
                Button("Dismiss All") {
                    sheetManager.dismissAll()
                }
            }
        }
    }
}

以上三种方案都能实现多个Sheet同步向下滑出关闭的效果,你可以根据自己的代码结构选择合适的方式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 06:10:26