我有一个要求,当触发任何alert 时,应该显示在应用程序的顶部视图.参考一些代码在互联网上的其他视图,我能够拿出解决方案,显示在视图或甚至表,如果它是顶部视图.
但是,alert 上的按钮或任何点击手势都不起作用.
注:我有一个非常复杂的应用程序,所以我创建了一个快速示例应用程序.如果你复制我的代码并运行它,应用程序将自动打开一个工作表,然后显示一个警告,以显示我在应用程序中执行的工作流,除了在我的应用程序表打开手动按钮单击.
100
import SwiftUI
import Foundation
struct ContentView: View {
@StateObject var alertViewModel: AlertViewModel = AlertViewModel()
@State private var showSheet: Bool = false
var body: some View {
NavigationStack {
VStack(alignment: .center) {
Text("This is the main view. Opening sheet view...").padding(.top, 100.0)
Spacer()
}
.onAppear {
Task {
try await Task.sleep(nanoseconds: 3_000_000_000)
showSheet = true
try await Task.sleep(nanoseconds: 3_000_000_000)
alertViewModel.showAlert = true
}
}
.environmentObject(alertViewModel)
.sheet(isPresented: $showSheet, content: {
SheetA()
})
.overlayModal(isPresented: $alertViewModel.showAlert, modalContent: alertViewModel.alertView)
}
}
}
struct SheetA: View {
var body: some View {
VStack {
Text("Sheet A to demo alert on top of all views. Alert will popup soon...").padding(.top, 100.0)
Spacer()
}
}
}
// MARK: CUSTOM ALERT CODE
class AlertViewModel: ObservableObject {
@Published public var showAlert: Bool = false
func alertView() -> some View {
return CustomAlertView()
}
}
struct CustomAlertView: View {
@State private var alertHostingController: UIHostingController<AnyView>?
@EnvironmentObject var alertViewModel: AlertViewModel
var body: some View {
ZStack {
Color.gray.opacity(0.3).ignoresSafeArea()
VStack {
}.onAppear {
showAlert()
}
}
}
@ViewBuilder
func alertContent() -> some View {
GeometryReader { geometry in
VStack {
Image(systemName: "info.circle").resizable().frame(width: 20, height: 20)
.padding(.top, 30).foregroundColor(.blue)
Text("Hello World").foregroundColor(.black).font(.title2).bold().multilineTextAlignment(.center)
.padding([.leading, .trailing], 20.0).padding(.top, 12.0)
Spacer()
Text("This is an alert to show detailed message for the app.").foregroundColor(Color.secondary).font(.body).multilineTextAlignment(.center)
.padding([.leading, .trailing], 20.0).padding(.top, 12.0)
.onTapGesture {
print("Testing alert tap on message")
}
Spacer()
Button {
print("Button tapped")
} label: {
Text("Click Me").buttonBorderShape(.roundedRectangle)
}
.padding(.bottom, 20.0)
}
.fixedSize(horizontal: false, vertical: true)
.background(Color.gray.opacity(0.5))
.cornerRadius(28)
.clipped()
.padding([.leading, .trailing], 5.0)
.position(x: geometry.size.width/2, y: geometry.size.height/2)
.frame(minWidth: 250, maxWidth: 350)
//.allowsHitTesting(false)
}
}
func showAlert() {
let swiftUIView = alertContent()
alertHostingController = UIHostingController(rootView: AnyView(swiftUIView))
alertHostingController?.view.backgroundColor = .clear
alertHostingController?.view.frame = CGRect(x: 0, y: UIScreen.main.bounds.height, width: UIScreen.main.bounds.width - 44.0, height: 0)
if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let window = windowScene.windows.first, let hostingController = alertHostingController {
window.addSubview(hostingController.view)
hostingController.view.center.x = window.center.x
hostingController.view.center.y = window.center.y
}
}
func dismissAlert() {
UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseInOut) {
alertHostingController?.view.frame = CGRect(x: 0, y: UIScreen.main.bounds.height, width: UIScreen.main.bounds.width, height: 0)
alertHostingController?.view.alpha = 0
}
Task {
await MainActor.run {
alertHostingController?.view.removeFromSuperview()
alertHostingController = nil
alertViewModel.showAlert = false
}
}
}
}
// MARK: OVERLAY CODE
struct OverlayView<OverlayContent: View>: ViewModifier {
@Binding var isPresented: Bool
var modalContent: OverlayContent
func body(content: Content) -> some View {
GeometryReader { _ in
ZStack {
content
VStack {
if isPresented {
modalContent
} else {
Spacer()
}
}
}
}
}
}
extension View {
@ViewBuilder
func overlayModal<ModalContent: View>(isPresented: Binding<Bool>, @ViewBuilder modalContent: @escaping () -> ModalContent) -> some View {
modifier(OverlayView(isPresented: isPresented, modalContent: modalContent()))
}
}
你知道为什么我的敲击手势不起作用吗?欢迎任何其他解决方案,在所有视图之上呈现自定义alert .