Multiple NavigationLink in SwiftUI - swiftui

Can you have multiple NavigationLinks in SwiftUI? The following only displays the first Link:
struct Test : View {
var body: some View {
NavigationView {
NavigationLink(destination: Text("First")) {
Text("Visible")
}
NavigationLink(destination: Text("Second")) {
Text("Invisible")
}
//EDIT: Also Invisible
Text("Not rendered")
}
}
}
EDIT: Turns out everything under the first NavigationLink is not displayed

Put your views inside a VStack:
struct Test : View {
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: Text("First")) {
Text("Visible")
}
NavigationLink(destination: Text("Second")) {
Text("Invisible")
}
//EDIT: Also Invisible
Text("Not rendered")
}
}
}
}

Look you can definitely have multiple NavigationLinks but here you are doing one things wrong.
The body property returns a single View but here you are trying to return more than one views, which causes the error.
To Solve this issue we put them inside another View like a VStack or a HStack, like shown above in the answer given by kontiki.

Related

Does a LazyVStack remain "lazy" if it's inside a VStack?

Let's consider a list of 100 posts. According to Apple, if I layout them inside a LazyVStack:
the stack view doesn’t create items until it needs to render them
onscreen.
What if I embed that LazyVStack inside a VStack? Does it still load the views "as needed"?
struct MyView: View {
init() {
print("init...")
}
var body: some View {
Text("test")
}
}
struct ContentView: View {
var body: some View {
ScrollView {
VStack {
LazyVStack {
ForEach.init(0..<100) { int in
MyView()
}
}
}
}
}
}
Running the above code, as we scroll we can see more MyViews are init'd (by viewing the print statements in the console), so it seems like a LazyVStack in a VStack does indeed create it's content lazily. We can see the same is true when removing the VStack as well.

How to avoid spacer in NavigationView with Forms?

I have an NavigationView with an NavigationLink, when I get to the second View I have a strange spacer between the head and the beginning of my form:
This is my code:
struct SampleView: View {
var body: some View {
NavigationView {
VStack {
Form {
Section(header: Text("Hallo")){
Text("abc")
}
Section(header: Text("abc")){
Text("lorem")
Text("ispsum")
Button(action: {
//UIApplication.shared.open(eintrag.eintrag.url as URL)
}) {
Text("starten")
}
}
}
}.navigationBarTitle("Hello")
}
}
}
Is this a bug? How to avoid this? Its only when navigation in. If I set the view as my start view it looks like it should:
What do I need to do to get in on the top?

SwiftUI artefact after detail with list is presented

With the simple navigation-link structure below, I get a strange artefact after the detail view with a list is pushed on screen, as shown here https://youtu.be/LU9uluD5hEw.
If I include a section with a header, the view does not jerk up after the screen is loaded, but remains in its originally presented position. Anybody else experiencing this problem, or know how to fix it?
struct ContentView: View {
var body: some View {
NavigationView {
List {
NavigationLink(destination: DetailView()) {
Text("Link")
}
}
.navigationBarTitle("Master")
.listStyle(GroupedListStyle())
}
}
}
struct DetailView: View {
var body: some View {
List {
Text("Detail")
}
.navigationBarTitle("Detail")
.listStyle(GroupedListStyle())
}
}
This is especially annoying for picker details where I cannot add an empty section header as a workaround.
Workaround: It looks like a bug in TitleDisplayMode.large mode, because in the .inline mode such effect is not observed. So, the following might be considered as workaround if it is allowed by app design:
struct DetailView: View {
var body: some View {
List {
Text("Detail")
}
.navigationBarTitle("Detail", displayMode: .inline)
.listStyle(GroupedListStyle())
}
}

SwiftUI Navigation Multiple back button

When I push more than one view, multiple back buttons are visible in the navigation bar.
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink(destination:SecView()) {
Text("Primo")
}
}
}
}
struct SecView: View {
var body: some View {
NavigationView {
NavigationLink(destination:TerView()) {
Text("Secondo")
}
}
}
}
struct TerView: View {
var body: some View {
Text("Hello World!")
}
}
I would like to have only one back button per view.
Here is a screenshot of the problem.
There should only be a single NavigationView at the root of your navigation stack.
Remove the NavigationView block from SecView and you will then have a single navigation bar owned by ContentView.
as Gene said, there should only be a single NavigationView at the root of you navigation stack. This means that the next time you need to navigate to a page in a different View, you will add a NavigationLink but not wrap it in a NavigationView. So in the code that you initially posted, you need to remove the NavigationView from your SecView View but still keep the NavigationLink. See the code below:
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink(destination:SecView()) {
Text("Primo")
}
}
}
}
struct SecView: View {
var body: some View {
NavigationLink(destination:TerView()) {
Text("Secondo")
}
}
}
struct TerView: View {
var body: some View {
Text("Hello World!")
}
}

How to make SwiftUI NavigationLink work in edit mode?

I have a list of items. Clicking on one should push a new view to the navigation stack. I notice the NavigationLink doesn't work if the list is in edit mode. Is there a way to control that? I need it to work in edit mode.
List {
ForEach(segments) { segment in
NavigationLink(destination: EditSegmentView(segment: segment)) {
Text(segment.title)
}
}.onDelete(perform: onDelete)
.onMove(perform: onMove)
}.environment(\.editMode, $alwaysTrue)
I now have this working the way I wanted. I used a different NavigationLink initializer, with the tag and selection arguments. It seems to work well, but I don't know if this is the intended use of that initializer, because the documentation is painfully sparse.
#State var segmentSelection: Segment.ID? = nil
var body: some View {
NavigationView {
...
List {
ForEach(workout.segments) { segment in
NavigationLink(destination: EditSegmentView(segment: segment),
tag: segment.id,
selection: self.$segmentSelection) {
Text(segment.title)
}
.onTapGesture(perform: { self.segmentSelection = segment.id })
}.onDelete(perform: onDelete)
.onMove(perform: onMove)
}.environment(\.editMode, Binding.constant(.active))
...
}
}