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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 17:14:54