Thanks to part of an answer here, here's some working code.
First, I moved everything into an EnvronmentObject
to make things easier to pass to your second view. I also added a second toggle variable:
class Model: ObservableObject {
@Published var fieldValue = ""
@Published var showErrorMessage = false
@Published var showSecondView = false
}
Next, change two things in your ContentView
. I added a hidden NavigationLink
(with a isActive
parameter) to actually trigger the push, along with changing your Button
action to execute a local function:
struct ContentView: View {
@EnvironmentObject var model: Model
var body: some View {
NavigationView {
VStack {
TextField("My Field", text: $model.fieldValue).textFieldStyle(RoundedBorderTextFieldStyle())
NavigationLink(destination: SecondView(), isActive: $model.showSecondView) {
Text("NavLink")
}.hidden()
Button(action: {
self.checkForText()
}) {
Text("Next")
}
.alert(isPresented: self.$model.showErrorMessage) {
Alert(title: Text("Error"), message: Text("Please enter some text!"), dismissButton: .default(Text("OK")))
}
}
}
}
func checkForText() {
if model.fieldValue.isEmpty {
model.showErrorMessage.toggle()
} else {
model.showSecondView.toggle()
}
}
}
Toggling showErrorMessage
will show the Alert
and toggling `showSecondView will take you to the next view.
Finally, the second view:
struct SecondView: View {
@EnvironmentObject var model: Model
var body: some View {
ZStack {
Rectangle().fill(Color.green)
// workaround
.navigationBarBackButtonHidden(true) // not needed, but just in case
.navigationBarItems(leading: MyBackButton(label: "Back!") {
self.model.showSecondView = false
})
Text(model.fieldValue)
}
}
func popSecondView() {
model.showSecondView.toggle()
}
}
struct MyBackButton: View {
let label: String
let closure: () -> ()
var body: some View {
Button(action: { self.closure() }) {
HStack {
Image(systemName: "chevron.left")
Text(label)
}
}
}
}
This is where the above linked answer helped me. It appears there's a bug in navigation back that still exists in beta 6. Without this workaround (that toggles showSecondView
) you will get sent back to the second view one more time.
You didn't post any details on the second view contents, so I took the liberty to add someText
into the model to show you how to easily pass things into it can be using an EnvironmentObject
. There is one bit of setup needed to do this in SceneDelegate
:
var window: UIWindow?
var model = Model()
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let contentView = ContentView()
// Use a UIHostingController as window root view controller.
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView.environmentObject(model))
self.window = window
window.makeKeyAndVisible()
}
}
I noticed a slight change in this, depending on when your project was created (beta 6 declares an instance of contentView
where older versions do not). Either way, declare an instance of model
and then add the envoronmentObject
modifier to contentView
.