SwiftUI:NavigationLink 奇怪的行为

Posted

技术标签:

【中文标题】SwiftUI:NavigationLink 奇怪的行为【英文标题】:SwiftUI: NavigationLink weird behaviour 【发布时间】:2021-08-16 14:39:00 【问题描述】:

我正在尝试建立一个商店以便在 SwiftUI 流程中导航。 这个想法是每个屏幕都应该观察状态并使用 NavigationLink 进入下一个屏幕。

它似乎适用于推送一个视图,但是当我将几个视图推送到堆栈中时,它开始表现得很奇怪:视图会自行弹出。

幸运的是,我能够在一个单独的项目中重现它。当我从 2 移动到 3 时,会出现第三个屏幕,但 NavigationView 会重置为其原始状态 (ContentView):

import SwiftUI

@main
struct NavigationTestApp: App 
    
    var body: some Scene 
        WindowGroup 
            NavigationView 
                ContentView()
            .navigationViewStyle(StackNavigationViewStyle())
        
    




class Store: ObservableObject
    @Published var state: StoreState
    
    struct StoreState 
        var flowState: FlowState = .none
    
    
    enum FlowState 
        case none, one, two, three
    
    
    enum Action 
        case moveTo1, moveTo2, moveTo3
    
    
    init(state: StoreState) 
        self.state = state
    
    
    func send(_ action: Action) 
        
        switch action 
        case .moveTo1:
            state.flowState = .one
        case .moveTo2:
            state.flowState = .two
        case .moveTo3:
            state.flowState = .three
        
    
    
    


struct ContentView: View 
    
    @ObservedObject var store = Store(state: .init())
    
    
    var body: some View 
        VStack 
            Button(action: 
                store.send(.moveTo1)
            , label: 
                Text("moveTo1")
            )
            NavigationLink(
                destination: ContentView1().environmentObject(store),
                isActive: Binding(
                    get:  store.state.flowState == .one ,
                    set:  _ in
                    
                ),
                label: 
            )
        
        
    


struct ContentView1: View 
    @EnvironmentObject var store: Store
    
    var body: some View 
        VStack 
            Button(action: 
                store.send(.moveTo2)
            , label: 
                Text("moveTo2")
            )
            
            NavigationLink(
                destination: ContentView2().environmentObject(store),
                isActive: Binding(
                    get:  store.state.flowState == .two ,
                    set:  _ in
                    
                ),
                label: 
            )
        
    


struct ContentView2: View 
    @EnvironmentObject var store: Store
    
    var body: some View 
        VStack 
            Button(action: 
                store.send(.moveTo3)
            , label: 
                Text("moveTo3")
            )
            
            NavigationLink(
                destination: ContentView3().environmentObject(store),
                isActive: Binding(
                    get:  store.state.flowState == .three ,
                    set:  _ in
                    
                ),
                label: 
            )
        
    


struct ContentView3: View 
    @EnvironmentObject var store: Store
    
    var body: some View 
        
        Text("Hello, world!")
            .padding()
    


我错过了什么?

【问题讨论】:

尝试使用.isDetailLink(false),例如***.com/a/61707193/12299030 【参考方案1】:

我想出了一个解决方案。问题似乎是当您“移动到”下一个视图时,您的模型会从堆栈中弹出前一个视图。我(稍微)修改了它,以便系统现在可以确定导航堆栈上需要哪些视图。

不过,我不得不承认,我本来希望您的示例能够工作,因为我们只是声明堆栈中的(单个)视图。

因此,稍作修改的代码保留了导航堆栈上的先前视图(我还添加了一些打印语句以查看发生了什么):

import SwiftUI

class Store: ObservableObject
    @Published var state: StoreState

    struct StoreState 
        var flowState: FlowState = .none
    

    enum FlowState: Int 
        case none = 0, one, two, three
    

    enum Action 
        case moveTo1, moveTo2, moveTo3
    

    init(state: StoreState) 
        self.state = state
    

    func send(_ action: Action) 
        print("state: \(state), action: \(action)")
        switch action 
        case .moveTo1:
            state.flowState = .one
        case .moveTo2:
            state.flowState = .two
        case .moveTo3:
            state.flowState = .three
        
        print("new state: \(state)")
    




struct ContentView: View 

    @ObservedObject var store = Store(state: .init())


    var body: some View 
        VStack 
            Button(action: 
                print("moveTo1")
                store.send(.moveTo1)
            , label: 
                Text("moveTo1")
            )
            NavigationLink(
                destination: ContentView1().environmentObject(store),
                isActive: Binding(
                    get:  store.state.flowState.rawValue >= Store.FlowState.one.rawValue ,
                    set:  newValue in
                        store.state.flowState = .none
                        print("ContentView1: \(newValue)")
                    
                ),
                label: 
            )
        

    


struct ContentView1: View 
    @EnvironmentObject var store: Store

    var body: some View 
        VStack 
            Button(action: 
                print("moveTo2")
                store.send(.moveTo2)
            , label: 
                Text("moveTo2")
            )

            NavigationLink(
                destination: ContentView2().environmentObject(store),
                isActive: Binding(
                    get:  store.state.flowState.rawValue >= Store.FlowState.two.rawValue ,
                    set:  newValue in
                        store.state.flowState = .one
                        print("ContentView2: \(newValue)")
                    
                ),
                label: 
            )
        
    


struct ContentView2: View 
    @EnvironmentObject var store: Store

    var body: some View 
        VStack 
            Button(action: 
                print("moveTo3")
                store.send(.moveTo3)
            , label: 
                Text("moveTo3")
            )

            NavigationLink(
                destination: ContentView3().environmentObject(store),
                isActive: Binding(
                    get:  store.state.flowState.rawValue >= Store.FlowState.three.rawValue ,
                    set:  newValue in
                        store.state.flowState = .two
                        print("ContentView3: \(newValue)")
                    
                ),
                label: 
            )
        
    


struct ContentView3: View 
    @EnvironmentObject var store: Store

    var body: some View 

        Text("Hello, world!")
            .padding()
    



import PlaygroundSupport
PlaygroundPage.current.setLiveView(
    NavigationView 
        ContentView()
    .navigationViewStyle(StackNavigationViewStyle())
)

注意事项:

添加一个事件(又名操作)back 并确定视图模型中的新状态可能会更好,而不是让它在视图中执行。

【讨论】:

保持所有导航链接处于活动状态!就是这样!非常感谢:-)

以上是关于SwiftUI:NavigationLink 奇怪的行为的主要内容,如果未能解决你的问题,请参考以下文章

NavigationLink 中的 SwiftUI 按钮

SwiftUI 上的 NavigationLink 两次推送视图

SwiftUI:NavigationLink 内的水平 ScrollView 会中断导航

有没有办法向 NavigationLink 添加额外的功能? SwiftUI

无法单击列表中的 NavigationLink (SwiftUI)

需要帮助使 NavigationLink 在 SwiftUI 中工作