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

