По сути, у меня сложное приложение, в котором есть главное представление и представляют собой несколько панелей (представленных в виде .sheet или .fullScreenCover поверх основного вида). Одновременно в главном представлении будет активна только одна панель (аналогично Apple Maps).
У меня есть собственное оповещение (в виде полноэкранной обложки), созданное в виде модификатора, но всякий раз, когда я хочу представить оповещение на листе, мне приходится прикрепить к этому листу специальный модификатор оповещения. Это добавляет много дублированного кода в приложении, поскольку я прикрепляю модификаторы к каждому листу и пробую что-то, где модификатор просто привязан к основному представлению и всякий раз, когда должно быть представлено предупреждение, независимо от того, какая панель/лист открыто в главном представлении, поверх активного листа должно отображаться предупреждение.
Ниже приведен мой код. Я попытался создать небольшой пример работающего кода, поскольку мое приложение сложное:
Код: Выделить всё
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
}
}
Код: Выделить всё
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))
}
}
}
Как лучше всего этого добиться, представив оповещение как полное Кажется, крышка экрана не работает?
Подробнее здесь: https://stackoverflow.com/questions/793 ... in-swiftui