Programatic navigation for NavigationView using tag/selection or isActive

冷暖自知 提交于 2021-01-29 16:01:56

问题


NavigationLink has an initializer NavigationLink(destination:, tag:, selection:, label:) that is supposed to be a hidden NavigationLink that gets active when selection == tag. Similiar to NavigationLink(destination:isActive:label:).

Now I wondered, could I use this to have a property in a model that can be used to jump between pages arbitrarily? Aka, to support programatic navigation for NavigationView?

Something like this:

import SwiftUI

enum NavStep {
    case step1
    case step2
}

class NavModel: ObservableObject {
    @Published var step: NavStep? = .step1
}

struct Page1View: View {

    @EnvironmentObject var navModel: NavModel

    var body: some View {
        VStack(spacing: 20) {
            // Hidden link from Page1 -> Page2 that gets active when model.step is set to .step2
            NavigationLink(destination: Page2View(), tag: NavStep.step2, selection: $navModel.step) {
                EmptyView()
            }
            Text("Page 1")
            Button("Go to Page 2") {
                self.navModel.step = .step2
            }
        }
        .navigationBarTitle("Page 1")
    }

}

struct Page2View: View {

    @EnvironmentObject var navModel: NavModel

    var body: some View {
        VStack(spacing: 20) {
            Text("Page 2")
            Button("Go to Page 1") {
                self.navModel.step = .step1
            }
        }
        .navigationBarTitle("Page 2")
    }

}

struct ProgrammaticNavigationExample: View {

    var body: some View {
        NavigationView {
            Page1View()
        }
        .environmentObject(NavModel())
    }

}

struct ProgrammaticNavigationExample_Previews: PreviewProvider {
    static var previews: some View {
        ProgrammaticNavigationExample()
    }
}

Very well, works for two pages, you can navigate programatically by setting the step property. But, now I wondered, how could this be extended to another, third page?

When I try to do this naively, setting 'model.step = .step3' breaks the navigation link in the first page and we're back to page 1. Even if I model this using two boolean properties 'enteredStep2' / 'enteredStep3' that could be set accordingly it gets flaky when trying to go back by setting these properties.

Any ideas how programmatic navigation could be enabled with this API (or in some other way)? Or any clue why NavigationView/NavigationLink behaves like it does for the examples?


回答1:


It seems it is currently not possible to use this API to build programatic navigation over multiple steps (see Asperis comment for more information).

You can only use NavigationLink(destination:, tag:, selection:, label:) to make a programmatic decision on what View to show next, like:

struct ProgrammaticNavigationExampleView: View {

    enum NavDestination {
        case red
        case green
    }

    @State var destination : NavDestination?

    var body: some View {
        VStack(spacing: 20) {
            NavigationLink(destination: Color.red, tag: NavDestination.red, selection: $destination) {
                EmptyView()
            }
            NavigationLink(destination: Color.green, tag: NavDestination.green, selection: $destination) {
                EmptyView()
            }
            Text("Page 1")
            Button("Show random page") {
                self.destination = [.red, .green].randomElement()!
            }
        }
        .navigationBarTitle("Page 1")
    }

}

struct ProgrammaticNavigationExample_Previews: PreviewProvider {
    static var previews: some View {
        NavigationView {
            ProgrammaticNavigationExampleView()
        }
    }
}


来源:https://stackoverflow.com/questions/61920405/programatic-navigation-for-navigationview-using-tag-selection-or-isactive

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!