Skip to content

Instantly share code, notes, and snippets.

@darrarski
Created April 7, 2021 15:56
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save darrarski/22edfc682dc918f6f6cc5e441429c6cf to your computer and use it in GitHub Desktop.
Save darrarski/22edfc682dc918f6f6cc5e441429c6cf to your computer and use it in GitHub Desktop.
Lazy navigation in SwiftUI - animations issue
// Based on "Lazy navigation in SwiftUI" blogpost by Majid Jabrayilov
// Blogpost url: https://swiftwithmajid.com/2021/01/27/lazy-navigation-in-swiftui/
// This gist shows an issue with using conditional NavigationLinks.
// When using StackNavigationViewStyle push animations are not present.
import SwiftUI
@main
struct LazyNavApp: App {
var body: some Scene {
WindowGroup {
NavigationView {
FirstView()
}
.navigationViewStyle(StackNavigationViewStyle()) // comment this line to fix missing animations when pushing views
}
}
}
// MARK: - First screen
struct FirstView: View {
@State var second: Second?
var body: some View {
ZStack {
Color.yellow.ignoresSafeArea()
Button(action: { second = Second() }) {
Text("Present Second")
}
}
.navigationTitle("First")
.navigate(using: $second, destination: SecondView.init(second:))
}
}
// MARK: - Second screen
struct Second {}
struct SecondView: View {
var second: Second
@State var third: Third?
init(second: Second) {
self.second = second
}
var body: some View {
ZStack {
Color.green.ignoresSafeArea()
Button(action: { third = Third() }) {
Text("Present Third")
}
}
.navigationTitle("Second")
.navigate(using: $third, destination: ThirdView.init(third:))
}
}
// MARK: - Third screen
struct Third {}
struct ThirdView: View {
var third: Third
var body: some View {
ZStack {
Color.gray.ignoresSafeArea()
Text("Third")
}
.navigationTitle("Third")
}
}
// MARK: - Navigation utils
extension NavigationLink where Label == EmptyView {
init?<Value>(
_ binding: Binding<Value?>,
@ViewBuilder destination: (Value) -> Destination
) {
guard let value = binding.wrappedValue else {
return nil
}
let isActive = Binding(
get: { true },
set: { newValue in if !newValue { binding.wrappedValue = nil } }
)
self.init(destination: destination(value), isActive: isActive, label: EmptyView.init)
}
}
extension View {
@ViewBuilder
func navigate<Value, Destination: View>(
using binding: Binding<Value?>,
@ViewBuilder destination: (Value) -> Destination
) -> some View {
background(NavigationLink(binding, destination: destination))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment