How to properly manage view focus while pushing multiple views to NavigationStack path in SwiftUI iOS 17+

77 views Asked by At

I'm trying to save the state of my NavigationPath for my NavigationStack in SwiftUI by pushing all the views to the stack at once. That way if the user taps the Back button, they will still see the views in order (like an onboarding flow). The views are added to the stack and the onAppear action is called for each.

My problem is that when the user taps the Back button, onAppear is not called again. It seems as if the Views are all still in focus. In a normal path operation, such as tapping the Four Button, the Four View appears firing its onAppear action, then tapping the Back button returns to Three View firing its onAppear function. So the issue only occurs when pushing multiple views to the stack.

After appending the views to the stack and navigating Back (removing from the stack), I'm expecting the views to fire onAppear again. This is currently not happening.

Maybe I'm making things more complicated than they need to be... so if anyone has any tips on recovering navigation path state I'd appreciate it.

enum Destination: String{
    case oneView
    case twoView
    case threeView
    case fourView
}

struct PageView: View {
    var title: String
    @Binding var path: [Destination]
    
    var body: some View {
        Text(title)
            .onAppear(perform: {
                print("\(title) appear")
            })
            .navigationBarBackButtonHidden()
            .toolbar(content: {
                ToolbarItem(placement: .topBarLeading) {
                    Button("Back") {
                        path.removeLast()
                    }
                }
                if title == "Three View" {
                    ToolbarItem(placement: .topBarTrailing) {
                        Button("Four View") {
                            path.append(.fourView)
                        }
                    }
                }
            })
    }
}

struct ContentView: View {
    @State private var path: [Destination] = []
    
    var body: some View {
        NavigationStack(path: $path) {
            List {
                Button {
                    path.append(contentsOf: [.oneView, .twoView, .threeView])
                } label: {
                    Text("Three View")
                }
            }
            .navigationDestination(for: Destination.self) { destination in
                switch destination {
                case .oneView:
                    PageView(title: "One View", path: $path)
                case .twoView:
                    PageView(title: "Two View", path: $path)
                case .threeView:
                    PageView(title: "Three View", path: $path)
                case .fourView:
                    PageView(title: "Four View", path: $path)
                }
            }
        }
    }
}
0

There are 0 answers