SwiftUI iOS 15 NavigationLink pops out when press in textfield

Can anyone help? This problem appears in iOS 15 When I try to enter text in textfield it pop up

I used NavigationLink(destination: EmptyView()) { EmptyView() } But it doesn’t fix the problem

https://drive.google.com/file/d/1XN7fzKR-Tod-KyAUVjPmdsg1WZgmxDKJ/view?usp=drivesdk

Can you show enough code to reproduce the issue as text using Code Block? Not many readers would like to dive in to the external site.

@gamersjo I also had the same issue specific with iOS 15 Only, When navigating to the next screens, the Parent view gets reinitialized and pops back to the same screen.

Same for me, why is NavigationLink so broken!? In iOS 14 we had to have EmptyView navigation links, these no longer seem to fix the issue in 15...

Hi, I had the same problem with iOS15, and StackNavigationViewStyle worked for me.

NavigationView {
  Your code
}
.navigationViewStyle(StackNavigationViewStyle())

I could never find a reliable solution to this horrible bug. So I decided to create a custom NavigationLink, using Introspect (https://github.com/siteline/SwiftUI-Introspect). This works way better than expected, because all swiftui related functions continue working as usual. Seems like the bug is specifically with NavigationLink.

private struct NavigationLinkImpl<Destination: View, Label: View>: View {
    let destination: () -> Destination?
    @State var isActive = false
    @ViewBuilder let label: () -> Label

    var body: some View {
        NavigationLinkImpl1(destination: destination, isActive: $isActive, label: label)
    }
}

private struct NavigationLinkImpl1<Destination: View, Label: View>: View {
    let destination: () -> Destination
    @Binding var isActive: Bool
    @ViewBuilder let label: () -> Label
    @State var model = Model()

    var body: some View {
        Button(action: action, label: label)
            .introspectNavigationController(customize: handle)
            .id(isActive)
    }

    func handle(nav: UINavigationController) {
        if isActive {
            if model.destination == nil {
                let dest = UIHostingController<Destination>(rootView: destination())
                nav.pushViewController(dest, animated: true)
                model.destination = dest
            }
        } else {
            if let dest = model.destination {
                if let i = nav.viewControllers.lastIndex(of: dest) {
                    nav.setViewControllers(.init(nav.viewControllers.prefix(i + 1)), animated: true)
                }
                model.destination = nil
            }
        }
        if isActive != model.contains(nav: nav) { // detect pop
            isActive = model.contains(nav: nav)
        }
    }

    final class Model {
        var destination: UIHostingController<Destination>?
        func contains(nav: UINavigationController) -> Bool { destination.map { nav.viewControllers.contains($0) } ?? false }
    }

    func action() { isActive = true }
}

extension NavigationLink {
    init<Destination: View, Label: View>(destination: @autoclosure @escaping () -> Destination, @ViewBuilder label: @escaping () -> Label) {
        self.init(body: NavigationLinkImpl(destination: destination, label: label))
    }

    init<Destination: View, Label: View>(destination: @autoclosure @escaping () -> Destination, isActive: Binding<Bool>, @ViewBuilder label: @escaping () -> Label) {
        self.init(body: NavigationLinkImpl1(destination: destination, isActive: isActive, label: label))
    }

    init<Destination: View>(_ text: String, destination: @autoclosure @escaping () -> Destination, isActive: Binding<Bool>) {
        self.init(destination: destination(), isActive: isActive) { Text(text) }
    }

    init<Destination: View>(_ text: String, destination: @autoclosure @escaping () -> Destination) {
        self.init(destination: destination()) { Text(text) }
    }
}

Put this in a file, and your existing NavigationLinks will work just fine. Tested in ios 14 and 15

My navigation was auto to pop after I presented a sheet. I used solution of @ArutyunSWAG, and made it shorter. Hope it can help someone.

import SwiftUI
import Introspect

struct NavigationLinkImplement<Destination: View, Label: View>: View {
  let destination: () -> Destination
  @ViewBuilder let label: () -> Label
  @State private var isActive = false
  @State private var nav: UINavigationController?
   
  var body: some View {
    Button(action: action, label: label)
      .introspectNavigationController { nav in
        self.nav = nav
      }
  }
   
  func action() {
    let dest = UIHostingController<Destination>(rootView: destination())
    nav?.pushViewController(dest, animated: true)
  }
}

I'm having this issue too. When touching Textfield on a Navigation subview it pops back up to the parent view.

same issue when use NavigationStack

As always, Apple adds no-one-ever-uses features and brokes simple things.

SwiftUI iOS 15 NavigationLink pops out when press in textfield
 
 
Q