How can I use Navigation in alert using SwiftUI
I simplified your code snapshot for demo, but think the idea would be clear
struct TestNavigationFromAlert: View {
@State private var showUnpairAlert: Bool = false
@State private var activateLink: Bool = false
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: Text("Your Onboarding page"), isActive: $activateLink,
label: { EmptyView() })
// DEMO BUTTON - REMOVE IT
Button(action: { self.showUnpairAlert = true }) { Text("Alert") }
// YOUR CODE IS HERE
}
.alert(isPresented: $showUnpairAlert) {
Alert(title: Text("Unpair from \(checkForDeviceInformation())"), message: Text("Do you want to unpair the current pod?"), primaryButton: .destructive(Text("Unpair")) {
self.unpairAndSetDefaultDeviceInformation()
}, secondaryButton: .cancel())
}
}
}
func checkForDeviceInformation() -> String {
// YOUR CODE IS HERE
return "Stub information"
}
func unpairAndSetDefaultDeviceInformation() {
// YOUR CODE IS HERE
DispatchQueue.main.async {
self.activateLink = true
}
}
}
Navigating back to main menu View in SwiftUI with Alert Button
To achieve what you are expecting, you actually need to add the NavigationView
inside ContentView
, if that's your main view. Because you navigate from ContentView
to GameView
, and what you are asking here is how to navigate back.
Applying the concept above, you can just dismiss GameView
to go back to the in view.
Here is a sample code to achieve that:
Example of main view:
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink {
GameView()
// This is how you hide the "<Back" button, so the user
// can navigate back only when tapping the alert
.navigationBarHidden(true)
} label: {
Text("Go to game view")
}
}
}
}
Example of game view:
struct GameView: View {
// This variable will dismiss the view
@Environment(\.presentationMode) var presentationMode
@State private var questionCounter = 1
@State var userAnswer = ""
@State private var alertTitle = ""
@State private var gameOver = false
// No need to use this variable
// @State private var menuNavigation = false
var body: some View {
// No need to have a NavigationView
// NavigationView {
// ZStack has no function apparently...
// ZStack{
// No need to have a NavigationLink
// NavigationLink(destination:ContentView(), isActive: $menuNavigation){
// Text("")
//}
VStack {
Text("Give the answer")
TextField("Give it", text: $userAnswer)
Button("Submit", action: answerQuestion)
}
.alert(isPresented: $gameOver) {
Alert(title: Text(alertTitle),
dismissButton: Alert.Button.default(
Text("Back to menu"), action: {
// This is how you go back to ContentView
presentationMode.wrappedValue.dismiss()
}
)
)
}
}
func answerQuestion() {
questionCounter += 1
if questionCounter == 2 {
gameOver.toggle()
alertTitle = "Game Over"
}
}
}
SwiftUi: Navigating to a secondary page through Button Alert Confirmation
To get the Back
button you need a NavigationLink
vs a popover
. You can just "hide" the NavigationLink
next to your Button
import SwiftUI
struct ConfirmNavView: View {
@State var txtField1 : String = ""
@State var txtField2: String = ""
@State var txtField3: String = ""
@State var txtField4: String = ""
@State var txtField5 : String = ""
@State private var showingAlert = false
@State private var showingView = false
var body: some View {
NavigationView{
HStack{
Button(action: {
self.showingAlert = true
}) {
Text("Submit")
.alert(isPresented:$showingAlert) {
Alert(title: Text("Would you like to go to second screen?"), message: Text("The second screen will pass all data from the first screen."), primaryButton:.destructive(Text("Continue")){
self.showingView = true
}, secondaryButton: .cancel(Text("Cancel")))
}
}
NavigationLink("View2", destination: View2(txtField1: self.$txtField1,
txtField2: self.$txtField2,
txtField3: self.$txtField3,
txtField4: self.$txtField4,
txtField5: self.$txtField5), isActive: $showingView).hidden().frame(width: 0, height: 0)
}
}
}
}
struct View2: View {
@Binding var txtField1 : String
@Binding var txtField2: String
@Binding var txtField3: String
@Binding var txtField4: String
@Binding var txtField5 : String
var body: some View {
VStack{
TextField("txtField1", text: $txtField1)
TextField("txtField2", text:$txtField2)
TextField("txtField3", text:$txtField3)
TextField("txtField4", text:$txtField4)
TextField("txtField5", text:$txtField5)
}
}
}
struct ConfirmNavView_Previews: PreviewProvider {
static var previews: some View {
ConfirmNavView()
}
}
Why is NavigationLink not working inside of a SwiftUI alert?
Because NavigationLink needs to be inside of a hierarchy using NavigationView. An alert is a modal presented outside of that structure.
If you would like to programmatically navigate, you can use the isActive
property of a NavigationLink
within the NavigationView
hierarchy.
struct ContentView : View {
@State private var alertIsPresented = false
@State private var navLinkActive = false
var body: some View {
NavigationView {
VStack{
Button("Present alert") {
alertIsPresented = true
}
.alert("End of available content", isPresented: $alertIsPresented) {
Button("Navigate") {
navLinkActive = true
}
}
NavigationLink(isActive: $navLinkActive, destination: { SearchView() }, label: {
EmptyView()
})
}
}
}
}
struct SearchView : View {
var body: some View {
Text("Search")
}
}
How to navigate using button with condition check in SwiftUI
You can do something like this:
NavigationView {
VStack {
NavigationLink(destination: Dashboard(userName: self.userId, password: self.password), isActive: $showDashboard) {
Text("")
}
Button(action: {
if self.userId.isEmpty || self.password.isEmpty {
self.isAlert = true
} else {
self.showDashboard = true
}
}) {
Text("Submit")
.foregroundColor(.green)
.font(.system(size: 22))
}
}
}
A thing to remember is that a NavigationLink is a button itself and when pressed it navigate to the destinationView
, the isActive
parameter is a way to force that to happen (without the user clicking the NavigationLink). As of now I'm not sure how to embed logic into NavigationLinks.
Hope this helps :)
EDIT:
Another thing you can do is the following:
NavigationLink(destination:Dashboard(userName: self.userId, password: self.password)) {
Text("Submit")
}.disabled(self.userId.isEmpty || self.password.isEmpty )
This would disable the NavigationLink until both input fields are not empty.
Related Topics
Define Struct That Is Treated Like a Class in Swift
Extending Typed Array by Conforming to a Protocol in Swift 2
Referencing Self in Super.Init
Obtain Nsurl from Uiimagepickercontroller
Initializing Property via Closure
Crash When Running on Device After Second Launch
Programmatically Scroll Nsscrollview to the Right
How to Convert a Unsafemutablepointer<Void> to Uint8
How to Find the Time Interval Remaining from Nstimer
How to Properly Check If Non-Optional Return Value Is Valid
Swift Package Manager Unable to Compile Ncurses Installed Through Homebrew
Making a Uibutton a % of the Screen Size
Images Inaccessible from Asset Catalog in a Swiftui Framework
Cast to Different C Struct Unsafe Pointer in Swift
Swiftui - Make Toolbar's Navigationlink Use Detail View
Hovering a Modelentity in Front of Arcamera
Attributed Text, Replace a Specific Font by Another Using Swift