Post

Replies

Boosts

Views

Activity

Reply to SwiftUI NavigationLink pops out by itself
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
Jan ’22
Reply to SwiftUI iOS 15 NavigationLink pops out when press in textfield
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
Jan ’22