Navigationview Pops Back to Root, Omitting Intermediate View

NavigationView pops back to root, omitting intermediate view

Currently placing a NavigationLink in the .navigationBarItems may cause some issues.

A possible solution is to move the NavigationLink to the view body and only toggle a variable in the navigation bar button:

struct ModelListView: View {
@State var modelViewModel = ModelViewModel()
@State var isAddLinkActive = false // add a `@State` variable

var body: some View {
List(modelViewModel.modelValues.indices) { index in
NavigationLink(
destination: ModelEditView(model: $modelViewModel.modelValues[index]),
label: {
Text(modelViewModel.modelValues[index].titel)
}
)
}
.background( // move the `NavigationLink` to the `body`
NavigationLink(destination: ModelAddView(modelViewModel: $modelViewModel), isActive: $isAddLinkActive) {
EmptyView()
}
.hidden()
)
.navigationBarTitleDisplayMode(.inline)
.navigationBarItems(trailing: trailingButton)
}

// use a Button to activate the `NavigationLink`
var trailingButton: some View {
Button(action: {
self.isAddLinkActive = true
}) {
Image(systemName: "plus")
}
}
}

SwiftUI pushed View through Navigationview pops back after dismissing sheet

Currently placing a NavigationLink in the navigationBarItems may cause some issues.

Try removing the NavigationLink from navigationBarItems and put it the background:

struct homeView: View {
@State var showSearch: Bool = false
var body: some View {
NavigationView {
Text("home")
// move `NavigationLink` outside `navigationBarItems`
.background(NavigationLink("", destination: SearchContentView(), isActive: $showSearch))
.navigationBarTitle("", displayMode: .inline)
.navigationViewStyle(StackNavigationViewStyle())
.navigationBarItems(trailing: HStack {
Button("search", action: {
showSearch.toggle()
})
})
}
}
}

SwiftUI NavigationView pop itself when a datasource is finished loading

This happens because you're specifying id as item itself, and when list updated there's no original item anymore, so it closes

If you just wanna modify items without adding/removing/reordering, you can make index your item id:

NavigationView {
List(viewModel.dataSource.indices, id: \.self) { i in
let item = viewModel.dataSource[i]
NavigationLink(destination: Text("\(item)")) {
Text("\(item)")
.padding()
}
}
}

But with more complex data you need to have your items Identifiable with unique ids, and you won't have such problem. Check out this example:

struct ContentView: View {
@ObservedObject var viewModel = ViewModel()

var body: some View {
NavigationView {
List(viewModel.dataSource) { item in
NavigationLink(destination: Text("\(item.value)")) {
Text("\(item.value)")
.padding()
}
}
}
}
}

class ViewModel: ObservableObject {
@Published private(set) var dataSource: [Item] = [1, 2, 3, 4, 5]

init() {
DispatchQueue.main.asyncAfter(deadline: .now() + 3) { [self] in // simulate calling webservice
// you're modifying value but id stays the same
self.dataSource[0].value = 99
}
}
}

struct Item: Identifiable, ExpressibleByIntegerLiteral {
let id = UUID()
var value: Int

init(integerLiteral value: IntegerLiteralType) {
self.value = value
}
}

How to remove the default Navigation Bar space in SwiftUI NavigationView

For some reason, SwiftUI requires that you also set .navigationBarTitle for .navigationBarHidden to work properly.

NavigationView {
FileBrowserView(jsonFromCall: URLRetrieve(URLtoFetch: applicationDelegate.apiURL))
.navigationBarTitle("")
.navigationBarHidden(true)
}

Update

As @Peacemoon pointed out in the comments, the navigation bar remains hidden as you navigate deeper in the navigation stack, regardless of whether or not you set navigationBarHidden to false in subsequent views. As I said in the comments, this is either a result of poor implementation on Apple's part or just dreadful documentation (who knows, maybe there is a "correct" way to accomplish this).

Whatever the case, I came up with a workaround that seems to produce the original poster's desired results. I'm hesitant to recommend it because it seems unnecessarily hacky, but without any straightforward way of hiding and unhiding the navigation bar, this is the best I could do.

This example uses three views - View1 has a hidden navigation bar, and View2 and View3 both have visible navigation bars with titles.

struct View1: View {
@State var isNavigationBarHidden: Bool = true

var body: some View {
NavigationView {
ZStack {
Color.red
NavigationLink("View 2", destination: View2(isNavigationBarHidden: self.$isNavigationBarHidden))
}
.navigationBarTitle("Hidden Title")
.navigationBarHidden(self.isNavigationBarHidden)
.onAppear {
self.isNavigationBarHidden = true
}
}
}
}

struct View2: View {
@Binding var isNavigationBarHidden: Bool

var body: some View {
ZStack {
Color.green
NavigationLink("View 3", destination: View3())
}
.navigationBarTitle("Visible Title 1")
.onAppear {
self.isNavigationBarHidden = false
}
}
}

struct View3: View {
var body: some View {
Color.blue
.navigationBarTitle("Visible Title 2")
}
}

Setting navigationBarHidden to false on views deeper in the navigation stack doesn't seem to properly override the preference of the view that originally set navigationBarHidden to true, so the only workaround I could come up with was using a binding to change the preference of the original view when a new view is pushed onto the navigation stack.

Like I said, this is a hacky solution, but without an official solution from Apple, this is the best that I've been able to come up with.

SwiftUI Navigation. View pops immediately after being pushed. How to fix?

You might be running into the bug where views pop immediately if there's exactly two navigation links. Try inserting a NavigationLink with EmptyViews as shown as a temporary bandaid.

        NavigationLink(destination: EmptyView()) {
EmptyView()
}

You can find more info here:
https://forums.swift.org/t/14-5-beta3-navigationlink-unexpected-pop/45279

Issue with popping to a previous view (navigation controller)

First, it looks like your NavigationController is not your Initial View Controller. The arrow is pointing at the one in the middle, not the one on the left as I would expect.

As to your follow up question, removing the navigation bar at the top is easy enough.

Just add this to your UIViewControllers:

override func viewWillAppear(animated: Bool) {
self.navigationController?.navigationBar.hidden = true
}

As far as I know you have to remove it for each UIViewController in your stack.

One other thing. Your code for "back" can be simplified:

@IBAction func back(sender: AnyObject) {
self.navigationController?.popViewControllerAnimated(true)
}

In Swift 3:

@IBAction func gobackTapped(sender: AnyObject) {
_ = self.navigationController?.popViewController(animated: true)
}

The syntax is dumb, but this is how it is right now. I would assume at some point popViewController will be marked as a @discardableResult



Related Topics



Leave a reply



Submit