SwiftUI: come si chiude un foglio e si avvia un foglio diverso da ContentView?
Per la mia app, ho una schermata di benvenuto che introduce ciò che fa l'app e consente all'utente di creare il suo primo elemento. Quando l'utente fa clic sul pulsante, vorrei chiudere il foglio "welcomeScreen" e quindi avviare il foglio "newRemindr".
Ho provato a raggiungere questo obiettivo creando un oggetto osservabile con un valore booleano 'addNewTrigger' impostato su false. Quando faccio clic sul pulsante Aggiungi nuovo promemoria sulla schermata di benvenuto, l'azione del pulsante provoca la chiusura della schermata di benvenuto e attiva il valore booleano "addNewTrigger" su True. (Ho verificato che funzioni con Print Statements). Tuttavia, la visualizzazione del contenuto sta ascoltando lo stesso oggetto osservato per avviare il foglio "newRemindr" ma tale azione non sembra funzionare.
Qualcuno può dare un'occhiata al codice e vedere dove sbaglio? Oppure suggerire un'alternativa in grado di fornire il tipo di funzionalità.
Apprezzo davvero tutto l'aiuto. Grazie!
Codice sotto...
Schermata di benvenuto:
import SwiftUI
import Combine
struct welcomeScreen: View {
@Environment(\.presentationMode) var mode: Binding<PresentationMode>
@ObservedObject var addNewReminder = showAddScreen()
var body: some View {
NavigationView {
ZStack (alignment: .center) {
LinearGradient(gradient: Gradient(colors: [Color.white, Color.white, Color.gray]), startPoint: .top, endPoint: .bottom)
.edgesIgnoringSafeArea(.all)
Image("Ellipse2")
.offset(y: -475)
VStack {
Spacer()
Text("Welcome to")
.foregroundColor(.white)
.fontWeight(.bold)
Image("RemindrLogoWhite")
Spacer()
Text("What is remindr?")
.font(.title)
.fontWeight(.bold)
.padding(.bottom, 25)
Text("Remindr is a simple app designed to help you schedule random reminders with the goal of clearing your mind.\n\nRemind yourself to check in with your body, set up positive affirmations, set your intentions; Whatever it is, the power is up to you.")
.padding(.horizontal, 25)
.padding(.bottom, 25)
Text("Click below to get started:")
.fontWeight(.bold)
// Add New Reminder Button
Button(action: {
self.mode.wrappedValue.dismiss()
print("Add Reminder Button from Welcome Screen is Tapped")
self.addNewReminder.addNewTrigger.toggle()
print("var addNewTrigger has been changed to \(self.addNewReminder.addNewTrigger)")
}) {
Image("addButton")
.renderingMode(.original)
}.padding(.bottom, 25)
Spacer()
} .frame(maxWidth: UIScreen.main.bounds.width,
maxHeight: UIScreen.main.bounds.height)
}
.navigationBarTitle(Text(""), displayMode: .automatic)
.navigationBarItems(trailing: Button(action: {
self.mode.wrappedValue.dismiss()
}, label: {
Image(systemName: "xmark")
.foregroundColor(.white)
}))
}
}
}
Visualizzazione contenuto:
import SwiftUI
import CoreData
class showAddScreen: ObservableObject {
@Published var addNewTrigger = false
}
struct ContentView: View {
@Environment(\.managedObjectContext) var moc
@FetchRequest(entity: ReminderEntity.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \ReminderEntity.dateCreated, ascending: false)])
var reminder: FetchedResults<ReminderEntity>
// Sheet Control
@ObservedObject var addNewReminder = showAddScreen()
//@State private var showingAddScreen = false
@State var showWelcomeScreen = false
let emojiList = EmojiList()
//Toggle Control
@State var notifyOn = true
// Save Items Function
func saveItems() {
do {
try moc.save()
} catch {
print(error)
}
}
// Delete Item Function
func deleteItem(indexSet: IndexSet) {
let source = indexSet.first!
let listItem = reminder[source]
moc.delete(listItem)
}
// View Controller
var body: some View {
VStack {
NavigationView {
ZStack (alignment: .top) {
// List View
List {
ForEach(reminder, id: \.self) { notification in
NavigationLink(destination: editRemindr(reminder: notification,
notifyOn: notification.notifyOn,
emojiChoice: Int(notification.emojiChoice),
notification: notification.notification ?? "unknown",
notes: notification.notes ?? "unknown")) {
// Text within List View
HStack {
// MARK: TODO
//Toggle("NotifyOn", isOn: self.$notifyOn)
// .labelsHidden() // Hides the label/title
Text("\(self.emojiList.emojis[Int(notification.emojiChoice)]) \(notification.notification!)")
}
}
}
.onDelete(perform: deleteItem)
}.lineLimit(1)
// Navigation Items
.navigationBarTitle("", displayMode: .inline)
.navigationBarItems(
leading:
HStack {
Button(action: {
self.showWelcomeScreen.toggle()
}) {
Image(systemName: "info.circle.fill")
.font(.system(size: 24, weight: .regular))
}.foregroundColor(.gray)
// Positioning Remindr Logo on Navigation
Image("remindrLogoSmall")
.resizable()
.aspectRatio(contentMode: .fit)
//.frame(width: 60, height: 60, alignment: .center)
.padding(.leading, 83)
.padding(.top, -10)
},
// Global Settings Navigation Item
trailing: NavigationLink(destination: globalSettings()){
Image("settings")
.font(Font.title.weight(.ultraLight))
}.foregroundColor(.gray)
)
// Add New Reminder Button
VStack {
Spacer()
Button(action: { self.addNewReminder.addNewTrigger.toggle()
}) {
Image("addButton")
.renderingMode(.original)
}
.sheet(isPresented: $addNewReminder.addNewTrigger) {
newRemindr().environment(\.managedObjectContext, self.moc)
}
}
}
} .sheet(isPresented: $showWelcomeScreen) {
welcomeScreen()
}
}
}
}
Risposte
Innanzitutto quello che vedo è che usi diversi oggetti osservabili in entrambe le viste, ma dovresti usare lo stesso, quindi le modifiche apportate in una vista saranno disponibili anche per la seconda vista.
Ecco un modo per risolvere questo problema
struct welcomeScreen: View {
@Environment(\.presentationMode) var mode: Binding<PresentationMode>
@ObservedObject var addNewReminder: showAddScreen // << declare to be injected
// ... other code
e dentroContentView
} .sheet(isPresented: $showWelcomeScreen) {
welcomeScreen(addNewReminder: self.addNewReminder) // << inject !!
}
Alternativo: puoi rimuovere addNewReminder
da welcomeScreen
e lavorare con esso solo in ContentView
attivando sul foglio di benvenuto dismiss, come
} .sheet(isPresented: $showWelcomeScreen, onDismiss: {
// it is better to show second sheet with delay to give chance
// for first one to animate closing to the end
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.addNewReminder.addNewTrigger.toggle()
}
}
) {
welcomeScreen()
}