Mgwd
Mgwd

Reputation: 534

Why doesn't clearing the new iOS 16 SwiftUI NavigationPath to "pop to root" animate smoothly back to the root view?

I have a new iOS 16 SwiftUI NavigationStack with navigation determined by the NavigationDestination modifier which works fine.

My question is why doesn't it animate smoothly by sliding back to the root view when clearing the NavigationPath if you are more than one view deep within the stack?

It works if you are only one level deep, but anything lower than that causes "popping to root" to just jump back to the root view without the sliding animation.

Is this a "feature" or bug or am I doing something incorrectly?

Steps to re-create the issue

Demo of Issue

enter image description here

Demo Code (using Xcode 14.0 and iOS 16.0):

import SwiftUI
struct DemoPop: View {

    @State private var path = NavigationPath()
    
    var body: some View {
        
        VStack {
            
            NavigationStack(path: $path) {
                   
                List {
                    Section("List One") {
                        NavigationLink("Navigate to View 1", value: "View 1")
                        NavigationLink("Navigate to View 2", value: "View 2")
                    }
                }
                .navigationDestination(for: String.self) { textDesc in
                    
                    VStack {
                        Text(textDesc).padding()
                        Button("Navigate to View 3") {
                            path.append("View 3")
                        }.padding()
                        
                        Button("Pop to Root View") {
                            path.removeLast(path.count)
                        }.padding()
                    }
                }
                .navigationTitle("Test Pop To Root")
            }
        }
    }
}
    

struct DemoPop_Previews: PreviewProvider {
    static var previews: some View {
        DemoPop()
    }
}

Update 1:

Think the code above is correct so possibly a bug as mentioned in comments as I have just seen a YouTube video that exhibits the same behaviour - Youtube tutorial - around time line 19:25 - you will see pop to root just jumps back to start.

Update 2:

This has been fixed in iOS 16.2

Upvotes: 27

Views: 7597

Answers (2)

DrMickeyLauer
DrMickeyLauer

Reputation: 4674

Most likely a bug, please file a feedback w/ Apple.

That said, if you're on iOS, you can work around it with the following hack:

import UIKit

let animation = CATransition()
animation.isRemovedOnCompletion = true
animation.type = .moveIn
animation.subtype = .fromLeft
animation.duration = 0.3
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)

UIApplication.shared.keyWindow!.layer.add(animation, forKey: nil)
self.navigationPath.removeLast()

Upvotes: 5

user1922543
user1922543

Reputation:

This has been fixed by Apple on iOS 16.2

For iOS 16.0 and 16.1 here's a 100% working, one-liner solution. Add this SPM library to your codebase https://github.com/davdroman/swiftui-navigation-transitions (version 0.7.1 or later) and simply:

import NavigationTransitions
import SwiftUI

struct DemoPop: View {

    @State private var path = NavigationPath()

    var body: some View {
        NavigationStack(path: $path) {
            List {
                Section("List One") {
                    NavigationLink("Navigate to View 1", value: "View 1")
                    NavigationLink("Navigate to View 2", value: "View 2")
                }
            }
            .navigationDestination(for: String.self) { textDesc in

                VStack {
                    Text(textDesc).padding()
                    Button("Navigate to View 3") {
                        path.append("View 3")
                    }.padding()

                    Button("Pop to Root View") {
                        path.removeLast(path.count)
                    }.padding()
                }
            }
            .navigationTitle("Test Pop To Root")
        }
        .navigationTransition(.default) // one-liner ✨
    }
}


struct DemoPop_Previews: PreviewProvider {
    static var previews: some View {
        DemoPop()
    }
}

Upvotes: 6

Related Questions