Grundsätzlich habe ich eine komplexe Anwendung, in der es eine Hauptansicht gibt sind mehrere Panels (dargestellt in Form von .sheet oder .fullScreenCover über der Hauptansicht). Über der Hauptansicht ist jeweils nur ein Bereich aktiv (ähnlich wie bei Apple Maps).
Ich habe eine benutzerdefinierte Warnung (als Vollbild-Cover) in Form eines Modifikators erstellt, aber Immer wenn ich eine Warnung über einem Blatt anzeigen möchte, muss ich den benutzerdefinierten Warnungsmodifikator an dieses Blatt anhängen. Dadurch wird in der gesamten App eine Menge doppelter Code hinzugefügt, da ich jedem Blatt Modifikatoren hinzufüge und etwas ausprobiere, bei dem der Modifikator nur an die Hauptansicht gebunden ist und wann immer eine Warnung angezeigt werden soll, egal um welches Panel/Blatt es sich handelt In der Hauptansicht geöffnet, sollte über dem aktiven Blatt eine Warnung angezeigt werden.
Unten ist mein Code. Ich habe versucht, einen kleinen Beispiellaufcode zu erstellen, da meine App komplex ist:
Code: Select all
import SwiftUI
struct ContentView: View {
@State private var showSheet = false
@StateObject var viewModel: AppViewModel = AppViewModel()
var body: some View {
VStack {
Text("This is main view with multiple sheets.")
}
.padding(.bottom, 350.0)
.onAppear {
showSheet = true
}
.sheet(isPresented: $showSheet) {
SheetA().environmentObject(viewModel)
}
.customAlert(isPresented: $viewModel.showAlert) /// Wish to present an alert always from here, but the alert should be visible on top of any sheet that's open.
}
}
struct SheetA: View {
@EnvironmentObject var viewModel: AppViewModel
var body: some View {
VStack {
Text("This is sheet.")
Spacer()
Button {
viewModel.showAlertFromSheet()
} label: {
Text("Tap me")
}
}
.padding([.top, .bottom], 150.0)
.presentationDetents([.medium, .large], selection: $viewModel.panelDetent)
// Note: Works fine if I add this modifier to every sheet. But trying to avoid that.
//.customAlert(isPresented: $viewModel.showAlert)
}
}
class AppViewModel: ObservableObject {
@Published var panelDetent: PresentationDetent = .medium
@Published var showAlert: Bool = false
func showAlertFromSheet() {
// Make http request call and show an alert on failure
self.showAlert = true
}
}
Code: Select all
extension View {
func customAlert(isPresented: Binding) -> some View {
return modifier(CustomAlertView(isPresented: isPresented))
}
}
struct CustomAlertView: ViewModifier {
@Binding var isPresented: Bool
init(isPresented: Binding) {
self._isPresented = isPresented
}
func body(content: Content) -> some View {
content.fullScreenCover(isPresented: $isPresented) {
alertView123.background(CustomAlertBackground())
}
.transaction { transaction in
transaction.disablesAnimations = true
}
}
private var alertView123: some View {
GeometryReader { geometry in
if self.$isPresented.wrappedValue {
VStack {
Image(systemName: "info.circle.fill").resizable().frame(width: 32.0, height: 32.0)
.padding(.top, 30).foregroundColor(Color.blue)
Text("Alert Title").foregroundColor(Color.primary).font(.title2).bold().multilineTextAlignment(.center)
.padding([.leading, .trailing], 20.0).padding(.top, 12.0)
Spacer()
Text("Alert Message").foregroundColor(Color.secondary).font(.body).multilineTextAlignment(.center)
.padding([.leading, .trailing], 20.0).padding(.top, 12.0)
Spacer()
// Buttons
}.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(width: 350.0)
}
}
}
}
struct CustomAlertBackground: UIViewRepresentable {
func makeUIView(context: Context) -> UIView {
return InnerView()
}
func updateUIView(_ uiView: UIView, context: Context) {}
private class InnerView: UIView {
override func didMoveToWindow() {
super.didMoveToWindow()
superview?.superview?.backgroundColor = UIColor(Color.gray.opacity(0.25))
}
}
}
Was ist der beste Weg, dies zu erreichen, indem ich die Benachrichtigung als vollständig präsentiere? Bildschirmabdeckung scheint nicht zu funktionieren?