SwiftUI自定义Alert交互问题:禁用返回按钮、全屏遮罩等
iOS 16.4 SwiftUI自定义Alert问题解决方案
针对你遇到的三个自定义Alert相关问题,以下是具体的解决方法:
1. 弹出自定义Alert时禁用导航返回按钮
要同时禁用顶部返回按钮和侧滑返回手势,可结合两个SwiftUI修饰器:
.navigationBarBackButtonHidden(_:):隐藏顶部导航返回按钮.interactiveDismissDisabled(_:):禁用iOS 16+支持的侧滑返回手势
修改代码:
在ContentView2中添加这两个修饰器,绑定到Alert的显示状态:
struct ContentView2: View { @State private var showAlert = false var body: some View { VStack { Button("Show Alert") { showAlert = true } } .navigationTitle("settings") .customAlert(isPresented: $showAlert) .presentationDragIndicator(.visible) // 添加以下两行实现禁用返回 .navigationBarBackButtonHidden(showAlert) .interactiveDismissDisabled(showAlert) } }
2. 让遮罩层覆盖整个屏幕高度
原遮罩仅覆盖Sheet区域,是因为遮罩被添加在Sheet内部的视图层级中。要实现全屏遮罩,需要将遮罩和Alert放在独立的UIWindow层级,确保覆盖整个屏幕(包括Sheet后方的视图)。
修改CustomAlertView代码:
struct CustomAlertView: ViewModifier { @Binding var isPresented: Bool @State private var alertWindow: UIWindow? init(isPresented: Binding<Bool>) { self._isPresented = isPresented } func body(content: Content) -> some View { content .onChange(of: isPresented) { newValue in if newValue { showFullScreenScrimAndAlert() } else { alertWindow?.isHidden = true alertWindow = nil } } } private func showFullScreenScrimAndAlert() { guard let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene else { return } let window = UIWindow(windowScene: scene) window.backgroundColor = .clear window.windowLevel = .alert + 1 // 确保层级在Sheet和系统Alert之上 let hostingController = UIHostingController(rootView: fullScreenAlertView()) hostingController.view.backgroundColor = .clear window.rootViewController = hostingController window.isHidden = false alertWindow = window } @ViewBuilder private func fullScreenAlertView() -> some View { ZStack { // 全屏遮罩层 Color.gray.opacity(0.4) .ignoresSafeArea() .onTapGesture { isPresented = false } // 自定义Alert内容 alertContent() } } @ViewBuilder private func alertContent() -> some View { VStack { Text("title").foregroundColor(Color.black).font(.title2).bold().lineLimit(nil) .padding([.leading, .trailing], 20.0).padding(.top, 16.0) Spacer() Text("message").foregroundColor(Color.secondary).font(.body).bold().lineLimit(nil) .padding([.leading, .trailing], 20.0).padding(.top, 16.0) Spacer() Button { isPresented = false } label: { Text("Click Me") } .frame(width: 250.0, height: 20.0).padding(10.0).background(Color.blue) .foregroundColor(.white).font(.body) } .fixedSize(horizontal: false, vertical: true) .background(Color.gray) .cornerRadius(28) .clipped() .padding([.leading, .trailing], 5.0) .frame(width: 328.0) } }
3. 弹出自定义Alert时禁用Sheet的拖动指示器
Sheet的拖动指示器由.presentationDragIndicator(_:)控制,需要将Alert的显示状态传递到Sheet所在的视图,动态切换指示器的可见性。
步骤1:创建状态管理类
class AlertState: ObservableObject { @Published var isAlertShowing = false }
步骤2:传递状态到各视图
修改ContentView:
struct ContentView: View { @State private var showDetails = false @StateObject private var alertState = AlertState() var body: some View { NavigationStack { VStack { Button("Show Sheet A") { showDetails = true } } .sheet(isPresented: $showDetails) { ContentView1(alertState: alertState) } } } }
修改ContentView1,动态控制拖动指示器:
struct ContentView1: View { @State private var showDetails = false @ObservedObject var alertState: AlertState var body: some View { NavigationStack { VStack { Button("Show Sheet B") { showDetails = true } } .navigationDestination(isPresented: $showDetails) { ContentView2(alertState: alertState) } // 根据Alert状态切换指示器可见性 .presentationDragIndicator(alertState.isAlertShowing ? .hidden : .visible) } } }
修改ContentView2,绑定状态:
struct ContentView2: View { @ObservedObject var alertState: AlertState var body: some View { VStack { Button("Show Alert") { alertState.isAlertShowing = true } } .navigationTitle("settings") .customAlert(isPresented: $alertState.isAlertShowing) .navigationBarBackButtonHidden(alertState.isAlertShowing) .interactiveDismissDisabled(alertState.isAlertShowing) } }
内容的提问来源于stack exchange,提问作者tech_human
相关产品推荐
相关产品推荐

