SwiftUI presentationMode dismiss not work on specific case

I am presenting a sheet using the view modifier
.sheet(item: ...)

if the view you are presenting is wrap inside another view which only add a navigation view

let's say I have a view called ViewB with a dismiss button which called the presentation mode dismiss, that works

let' say I have another view called ViewBWithNavigationView
where it's calling ViewB inside the NavigationView and it also calling dismiss on the cancel button

the result of this is that the presentation mode dismiss will only works for the first view B the cancel button, it will no close the view if you click the button inside the view


Code Block
struct ViewBInsideNavigationView: View {
   
  @Environment(\.presentationMode) var presentationMode
  var body: some View {
    NavigationView {
      ViewB()
        .navigationBarTitle("View B", displayMode: .inline)
        .navigationBarItems(leading: Button("Cancel") {
          self.presentationMode.wrappedValue.dismiss()
        })
    }
  }
}


the call to self.presentationMode.wrappedValue.dismiss() inside ViewB is not trigger and the view is not dismiss

thanks


  • That's the same issue I'm having . Please anyone who knows reply the question . What to use instead of this environment value? I have Xcode 13.4.1

Add a Comment

Replies

Exactly same problem here, both on Xcode 12 and beta 12.2
Hi, I'm having this issue in a SwiftUI view presented modally using a UIHostingController from UIKit.

The self.presentationMode.wrappedValue.dismiss() is not working when the UIHostingController is presented modally like:

Code Block
navigationController?.present(controller, animated: true)


but it works when it's 'pushed' like:

Code Block
navigationController?.pushViewController(controller, animated: true)


I am facing the same issue when I try to present SwiftUI View modally using a UIHostingController. Is there any update on this ?
Same issue with me. The problem I am having with pushViewController is that I can't get the NavBar to hide without glitching up and away.

Any updates on how to fix this?
I tried to recreate the scenario that you presented. I wasn't entirely clear on what type of scenario you have. Below is the following that I was able to piece together.

Code Block Swift
struct ViewBB: View {
    var body: some View {
        Text("ViewBB")
    }
}
struct ViewB: View {
    @Environment(\.presentationMode) var presentationMode
    var body: some View {
        NavigationView {
            ViewBB()
            .navigationBarTitle("View B", displayMode: .inline)
            .navigationBarItems(leading: Button("Cancel") {
                self.presentationMode.wrappedValue.dismiss()
            })
        }
    }
}
struct ContentView: View {
    @State private var isPresetend: Bool = false
    var body: some View {
        VStack {
            Button(action: {
                self.isPresetend.toggle()
            }, label: { Text("Change view") })
            .sheet(isPresented: $isPresetend, content: { ViewB() })
            .navigationBarTitle("View A", displayMode: .inline)
        }
    }
}


Potentially this is already solved in an update to SwiftUI, but with the above code, the view does get dismissed via presentationMode. Unsure if this is entirely what the post was referring to, but if you could provide more of the logic/flow of what is happening to encounter this unexpected behavior, that would be appreciated.
I also have this problem exactly, on Xcode Version 12.2 (12B45b)

I will add a case where I experienced the same problem and how I did solve it.

I noticed also this problem when modifying my DataModel which is a @EnvironmentObject

When the button Save was pressed I was updating the dataModel and then dismissing the view with the presentationMode object. That was causing the dismissal to not work at all. Dismiss was working fine in the example below if the author was not valid so the model was not updated.

I narrowed the problem down to the dataModel.authors marked as @Published. If I do remove the annotation it will work. So It seems like a SwiftUI bug to me.

Cos I need the authors to be @Published so the changes are updated in the other views, a way to fix it is for this particular case is to have a @State var shouldSave: Bool and use the method onDisappear() to then set the values to the model.

Also using a delay with asyncAfter on the button Save do work cos the view will be first dismissed and then the values are updated.

See code for better context:

.toolbar {
     Button("Save") {
          shouldSave.toogle()
          self.presentationMode.wrappedValue.dismiss()
     }
}.onDisappear {
      guard shouldSave else { return }
      author.name = authorName
      if isValidAuthor(author) {
          dataModel.authors.append(author)
      }
}
  • That will just increase the LOC in Xcode . It won't be efficient at every cases

Add a Comment

Wow, its 1 year later and this bug is still not fixed. I used this brute force workaround inside a button action:

if var topController = UIApplication.shared.windows.first!.rootViewController {
	while let presentedViewController = topController.presentedViewController {
		topController = presentedViewController
	}
	topController.dismiss(animated: true)
}
  • This problem still appears to be a bug in Xcode 13.0 using SwiftUI. The dismiss() works fine in my case until I select a toggle button on that view. Then the dimiss() stops working.

Add a Comment

This issue still exists. The other way I was able to fix it is to make the navigationTitle form .large to .inline of the screen that calls the view in presentation mode.

One workaround would be to dismiss any open sheets before the app is sent to background. This is what I'm doing. Obviously not ideal, and will also close sheets if someone pops over to their control center or notifications/lock screen, but better than vital buttons not working. 😅

.onReceive(NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification)) { _ in
  self.isSheetPresented = false
}

I may have not got the issue correctly, but what I am making out of this problem is you are trying to dismiss ViewBInsideNavigationView using Navigation Views. But thats not how this code should be used. Navigation Views work like a tree, you create child views from root view, and when you go back, or dismiss the child view, you land BACK on the root view.

As per Apple documentation - https://developer.apple.com/documentation/swiftui/environmentvalues/dismiss, you use dismiss( or PresentationMode) to Pop the current view from a Navigation stack.

You are trying to dismiss root view here, because you have accessed presentationMode, on view where Navigation view starts, and trying to dismiss it. I don't think dismiss in Navigation views are supposed to work like that.

Please go through the above documentation for proper use.

PS: presentationMode is deprecated to dismiss in 17.0