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

SwiftUI:如何在自定义Alert后方添加全屏遮罩视图

实现自定义Alert的全屏遮罩与点击拦截

你之前尝试给ContentView添加背景无效,是因为这个背景属于ContentView的底层元素,自定义Alert是通过overlay添加在ContentView上方的,所以背景无法覆盖ContentView并拦截点击。正确的做法是在Alert的修饰器中,将全屏遮罩与Alert视图放在同一个overlay层里,置于ContentView上方、Alert下方,同时拦截遮罩的点击事件。

修改后的自定义Alert修饰器代码

import SwiftUI

struct CustomAlertView: ViewModifier {
    @Binding var isPresented: Bool

    init(isPresented: Binding<Bool>) {
        self._isPresented = isPresented
    }

    func body(content: Content) -> some View {
        content
            .overlay(alignment: .center) {
                if isPresented {
                    ZStack {
                        // 全屏半透明遮罩,拦截底层点击
                        Color.black.opacity(0.5)
                            .ignoresSafeArea()
                            .onTapGesture {
                                // 可选:点击遮罩关闭Alert,不需要则保留空实现拦截点击
                                // isPresented.toggle()
                            }
                        
                        // 原Alert内容
                        VStack {
                            Image(systemName: "info.circle")
                                .resizable()
                                .frame(width: 30.0, height: 30.0)
                                .padding(.top, 30)
                                .foregroundColor(.cyan)

                            Text("Error title")
                                .foregroundColor(.black)
                                .font(.title2)
                                .bold()
                                .lineLimit(nil)
                                .padding([.leading, .trailing], 24.0)
                                .padding(.top, 16.0)
                            
                            Spacer()
                            
                            Text("There was an error while processing your request.")
                                .foregroundColor(.black)
                                .font(.body)
                                .lineLimit(nil)
                                .padding([.leading, .trailing], 18.0)
                                .padding(.top, 16.0)
                            
                            Spacer()
                            
                            Button(action: { isPresented.toggle() }) {
                                Text("Ok")
                                    .foregroundColor(.white)
                                    .font(.largeTitle)
                                    .bold()
                            }
                            .padding(.bottom, 25.0)
                        }
                        .fixedSize(horizontal: false, vertical: true)
                        .background(Color.purple)
                        .cornerRadius(10)
                        .clipped()
                        .padding([.leading, .trailing], 5.0)
                        .frame(width: 328.0)
                    }
                }
            }
    }
}

extension View {
    func customAlert(isPresented: Binding<Bool>) -> some View {
        modifier(CustomAlertView(isPresented: isPresented))
    }
}

class CustomViewModel: ObservableObject {
    @Published var showAlert = false
    
    func doSomething() {
        self.showAlert = true
    }
}

修改后的ContentView代码

import SwiftUI

struct ContentView: View {
    @ObservedObject var viewModel: CustomViewModel = CustomViewModel()
    
    var body: some View {
        VStack {
            Spacer()

            Button(action: { viewModel.doSomething() }) {
                Text("Start").foregroundColor(Color.red).font(.title)
            }.padding(.bottom, 100.0)
        }
        .customAlert(isPresented: $viewModel.showAlert)
    }
}

关键改动说明

  • 将遮罩与Alert放在同一个overlay的ZStack中,确保遮罩覆盖全屏且位于Alert下方
  • 遮罩使用ignoresSafeArea()覆盖系统安全区域,保证全屏覆盖
  • 给遮罩添加空的onTapGesture,拦截点击事件,避免传递到底层ContentView的按钮
  • 移除ContentView中无效的background设置

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 11:15:38