如何在iOS 15及更早版本中支持SwiftUI程序化关闭视图
问题根源
@Environment 是视图层级的属性声明,编译期就会确定布局,不能放在运行时执行的 if #available 条件块中,因此你之前的条件声明写法本身不符合语法规则。
解决方案
方案1:最简兼容写法(推荐)
直接同时声明两个环境变量,iOS 14 及更低版本会自动忽略不存在的 \dismiss 环境变量,不会产生运行时问题,调用时按系统版本区分即可,同时完美避开 iOS 15 下 presentationMode 在 NavigationView 嵌套 TabView 场景下的失效 bug:
// 视图属性区直接同时声明两个环境变量 @Environment(\.presentationMode) var presentationMode @Environment(\.dismiss) var dismiss // 调用关闭逻辑时做版本判断 func closeView() { if #available(iOS 15, *) { dismiss() } else { presentationMode.wrappedValue.dismiss() } }
你提供的问题场景中,只要把 ChildView 按上面的写法修改,即可正常执行关闭操作。
方案2:全局封装(可选)
如果不想每个视图都重复声明两个环境变量,可以封装成自定义的全局关闭方法:
// 先定义自定义环境键 struct DismissAction: EnvironmentKey { static let defaultValue: () -> Void = {} } extension EnvironmentValues { var autoDismiss: () -> Void { get { self[DismissAction.self] } set { self[DismissAction.self] = newValue } } } // 在App入口或者根视图注入实现 @main struct YourApp: App { @Environment(\.dismiss) var dismiss @Environment(\.presentationMode) var presentationMode var body: some Scene { WindowGroup { RootView() .environment(\.autoDismiss, { if #available(iOS 15, *) { dismiss() } else { presentationMode.wrappedValue.dismiss() } }) } } } // 后续所有子视图直接调用即可 struct ChildView: View { @Environment(\.autoDismiss) var autoDismiss var body: some View { Button("POP") { autoDismiss() } } }
内容的提问来源于stack exchange,提问作者mota
相关产品推荐
相关产品推荐

