【问题标题】:SwiftUI: NavigationLink weird behaviourSwiftUI:NavigationLink 奇怪的行为
【发布时间】: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()
    }
}

我错过了什么?

【问题讨论】:

标签: swift swiftui


【解决方案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 并确定视图模型中的新状态可能会更好,而不是让它在视图中执行。

【讨论】:

  • 保持所有导航链接处于活动状态!就是这样!非常感谢:-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-08
  • 2015-07-20
  • 2010-10-03
  • 2021-07-12
  • 2013-10-04
  • 2019-01-23
相关资源
最近更新 更多