如何在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
相关产品推荐
相关产品推荐

