NavigationView and NavigationLink on button click in SwiftUI?
To fix your issue you need to bind and manage tag with NavigationLink
, So create one state inside you view as follow, just add above body.
@State var selection: Int? = nil
Then update your button code as follow to add NavigationLink
NavigationLink(destination: Text("Test"), tag: 1, selection: $selection) {
Button(action: {
print("login tapped")
self.selection = 1
}) {
HStack {
Spacer()
Text("Login").foregroundColor(Color.white).bold()
Spacer()
}
}
.accentColor(Color.black)
.padding()
.background(Color(UIColor.darkGray))
.cornerRadius(4.0)
.padding(Edge.Set.vertical, 20)
}
Meaning is, when selection and NavigationLink
tag value will match then navigation will be occurs.
I hope this will help you.
Button with NavigationLink and function call SwiftUI
The answer from Yodagama works if you were trying to present a sheet (because you called your navigation destination SheetView), but if you were trying to navigate to SheetView instead of present a sheet, the following code would do that.
struct LoginView: View {
@State var check = false
@State var answer = false
var body: some View {
NavigationView {
VStack{
Text("it doesn't work")
NavigationLink(destination: SheetView(), isActive: $answer, label: {
Button(action: {
answer = test(value: 2)
}, label: {
Text("Calculate")
})
})
}
}
}
func test(value: Int) -> Bool {
if value == 1 {
check = false
} else {
print("Succes")
check = true
}
return check
}
}
struct SheetView: View {
var body: some View {
NavigationView {
VStack{
Text("Test")
.font(.title)
}
}
}
}
SwiftUI - Opening a new view on button click
A NavigationLink
must be in view hierarchy, so instead of putting it in action we need to put some model there.
A sketch of possible approach
- destination model
enum MenuDestination: String, CaseIterable, Hashable {
case set1(MenuItem), set2
@ViewBuilder var view: some View {
switch self {
case .set1(let item): View1(item: item)
case .set2: SettingsView()
}
}
}
- navigation link in view
@State private var selection: MenuDestination?
var isActive: Binding<Bool> {
Binding(get: { selection != nil }, set: { selection = nil } )
}
var body: some View {
NavigationView {
ScrollView {
// ...
}
.background(
if let selection = selection {
NavigationLink(isActive: isActive, destination: { selection.view }) {
EmptyView()
}})
}
}
- button action assigns corresponding value, say
MenuItemAction
take as argument binding to selection and internally assign destination to that binding
MenuItemCircularGridView(imageName: item.imageName, menuItemName: item.name,
action: (menuOptionsAction.menuActions.first {$0.id == item.id})?.action($selection) ?? { _ in })
and MenuItemAction
inited with case of corresponding MenuDestination
See also this post
iOS SwiftUI - NavigationView NavigationLink: Close view with custom Button
You would use presentationMode.wrappedValue.dismiss()
. Take a look at this for more information. Here is how you would use it:
struct Login: View {
@AppStorage("userid") var userid: Int = 0
//Doesn't require anything to be passed in.
@Environment(\.presentationMode) var presentationMode
var body: some View{
VStack{
HStack{
Spacer()
Button(action: {
//Part where view is dismissed
presentationMode.wrappedValue.dismiss()
}) {
Image(systemName: "xmark")
.resizable()
.frame(width: 18, height: 18)
.foregroundColor(Color(UIColor(named: "IconColor")!))
}
.padding(.top, 12.0)
.padding(.trailing, 16.0)
}
Spacer()
}
}
}
You would still call this the same way, with a NavigationLink
like in the original question above.
Take a look at this answer for more info on dismissing. Also, note that this will disable the default swipe-back behavior, if you want to re-enable it, take a look here.
How to add buttons next to a Swiftui navigation link
I am taking the answer to your button question from this answer, so please give credit there. It is also possible to use a Button
with a programmatically triggered NavigationLink
in a .background()
as the NavigationLink
. That can be tricky to make it look stock, and this solution does what you want. This However, you also asked about the list, and that question is very important to understand.
First, if at all possible, avoid using id: \.self
in a List
, ForEach
, etc. The reason is it is very fragile, and will come back to bite you when you try to delete or move items, or if you have two of the "same" items in the list. You really should be using an identifiable struct for this. For this answer, I am using:
struct Fruit: Identifiable {
let id = UUID()
var type: String
// var color: Color, etc.
}
The view then becomes:
struct FruitListView: View {
// This array can have duplicate fruits and the ForEach is unaffected as the id's are different.
@State var fruits: [Fruit] = [Fruit(type: "apple"),
Fruit(type: "orange"),
Fruit(type: "orange"),
Fruit(type: "banana"),
Fruit(type: "banana"),
Fruit(type: "peach")]
var body: some View {
List {
// Since Fruit conforms to Identifiable, you do not need id:
ForEach(fruits) { fruit in
HStack {
Button {
fruits.removeAll(where: { $0.id == fruit.id })
} label: {
Image(systemName: "circle")
.imageScale(.large)
.foregroundColor(.accentColor)
}
.buttonStyle(PlainButtonStyle()) // This is necessary to capture the click
.frame(width: 40)
// .contentShape makes a larger tap area to take up the height of the row.
.contentShape(Rectangle())
// You can use fruit directly as it is a Fruit and an element of fruits
NavigationLink(destination: Text(fruit.type)) {
Text(fruit.type)
}
}
}
// This is a standard delete. Try implementing it in your code. You will likely get a crash.
.onDelete(perform: delete)
}
}
func delete(at offsets: IndexSet) {
fruits.remove(atOffsets: offsets)
}
}
SwiftUI: How to do additional work when clicking a NavigationLink?
For your described scenario here is the simplest way
NavigationView {
NavigationLink("Click Here", destination:
AnotherView()
.onAppear {
// any action having access to current view context
})
}
Verified as still valid with Xcode 13.3 / iOS 15.4
Navigating to detail view on button click in List Row(TableviewCell) in SwiftUI
Use the
.hidden()
modifier on thenavigationLink
to prevent the list item from capturing it's actionChange the
.buttonStyle
fromautomatic
to something else on the list item to prevent it from capturing the button action. (for exampleborderless
)
Working Demo
struct ContentView: View {
@State var selectedTag: Int?
var body: some View {
NavigationView {
List(1...10, id: \.self) { id in
HStack {
Text("Item \(id: id)")
Spacer()
Button("Show detail") { selectedTag = id }
.background(link(id))
}.buttonStyle(.borderless) /// ⚠️ on the item! **NOT** on the button!!!
}
}
}
func link(id: Int) -> some View {
NavigationLink("",
destination: Text("\(id) Selected"),
tag: id,
selection: $selectedTag
).hidden()
}
}
Button click go another page in swiftui
you could try this to go from LoginView
to WelcomeView
on your button click in LoginView
:
struct LoginView: View {
@State private var showWelcomeView = false
var body: some View {
NavigationView {
VStack {
Button(action: { showWelcomeView = true }) {
Text("Login")
.font(.custom(TextConstant.keyValues.front_name, size: 30))
.foregroundColor(.white)
.fontWeight(.bold)
.frame(minWidth: 0, maxWidth: .infinity)
.padding(.all,20)
.foregroundColor(.blue)
.background(LinearGradient(gradient: Gradient(colors: [.green, .green]), startPoint: .leading, endPoint: .trailing))
.cornerRadius(10)
}
NavigationLink("", destination: WelcomeView(), isActive: $showWelcomeView)
}
}
}
}
Related Topics
Disable Scroll on a Uiwebview Allowed
Using iOS Gamekit's "Bluetooth Bonjour" with Other Platforms
How Do iOS Push Notifications Work
How to Pretty Print Swift Dictionaries to the Console
Uitableviewcell Separator Disappearing in iOS7
Afnetworking: Handle Error Globally and Repeat Request
Launch Screen Storyboard Not Displaying Image
Checking Location Service Permission on iOS
Cocoapods Setup Stuck on Pod Setup Command on Terminal
How to Loop Through Uitableview's Cells
Nslayoutconstraint Crashes Viewcontroller
Using Custom Fonts with Xcode 6/iOS 8 Interface Builder Launch Screen