防止 SwiftUI 重置导航堆栈的状态

时间:2021-01-13 16:47:57

标签: swiftui

不知什么原因。到达堆栈的第四个子元素后,显示第三个子元素的绑定被重置。这里的问题是你不能再回去了。

这个问题会延续到第 5 个孩子身上 - 因此重置第 4 个孩子。

我什至试图从根注入一个环境对象,希望能缓解这个问题,但还是一样。

请尝试使用以下代码进行复制。

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

  var window: UIWindow?

  var globalEnvironment = GlobalEnviroment()

  func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    let contentView = ContentView().environmentObject(globalEnvironment)

    if let windowScene = scene as? UIWindowScene {
        let window = UIWindow(windowScene: windowScene)
        window.rootViewController = UIHostingController(rootView: contentView)
        self.window = window
        window.makeKeyAndVisible()
    }
  }

  // other callbacks
}

然后对于视图,我添加了日志记录,以便于查看问题

import SwiftUI

class GlobalEnviroment: ObservableObject {
  @Published var isPage2Active = false {
    didSet {
      print("? [2] something set this to \(isPage2Active)")
    }
  }
  @Published var isPage3Active = false {
    didSet {
      print("? [3] something set this to \(isPage3Active)")
    }
  }
  @Published var isPage4Active = false {
    didSet {
      print("? [4] something set this to \(isPage4Active)")
    }
  }
  @Published var isPage5Active = false {
    didSet {
      print("? [5] something set this to \(isPage5Active)")
    }
  }
}

struct ContentView: View {
  @State private var isDetailActive = false
  @EnvironmentObject var env: GlobalEnviroment

  var body: some View {
    print("? [root] redrawing...")
    return NavigationView {
      VStack {
        NavigationLink(destination: Page2(isActive: $env.isPage2Active)
                        .environmentObject(env),
                       isActive: $env.isPage2Active) {
          EmptyView()
        }
        Button(action: {
          env.isPage2Active = true
        }, label: {
          Text("Next")
        })
      }
    }
    .onReceive([env.isPage2Active].publisher.first(), perform: { response in
      print("? 2: \(response)")
    })
    .onReceive([env.isPage3Active].publisher.first(), perform: { response in
      print("? 3: \(response)")
    })
    .onReceive([env.isPage4Active].publisher.first(), perform: { response in
      print("? 4: \(response)")
    })
    .onReceive([env.isPage5Active].publisher.first(), perform: { response in
      print("? 5: \(response)")
    })
    .onAppear {
      print("? ============================================  >>>> ")
      print("? [root] appeared")
    }
    .onDisappear {
      print("? [root] disappear")
      print("? <<<<  ============================================ ")
    }
  }
}

struct Page2: View {
  @Binding var isActive: Bool
  @State private var isDetailActive = false
  @EnvironmentObject var env: GlobalEnviroment

  var body: some View {
    print("? [2] redrawing...")
    return VStack {
      Text("Page 2")
          .padding()
      NavigationLink(destination: Page3(isActive: $env.isPage3Active)
                      .environmentObject(env),
                     isActive: $env.isPage3Active) {
        EmptyView()
      }.isDetailLink(true)
      Button(action: {
        env.isPage2Active = false
      }, label: {
        Text("Back")
      })
        .padding()
      Button(action: {
        env.isPage3Active = true
      }, label: {
        Text("Next")
      })
    }
    .navigationBarBackButtonHidden(true)
    .onAppear {
      print("? ============================================  >>>> ")
      print("? [2] appeared")
    }
    .onDisappear {
      print("? [2] disappear")
      print("? <<<<  ============================================ ")
    }
  }
}

struct Page3: View {
  @Binding var isActive: Bool
  @EnvironmentObject var env: GlobalEnviroment

  var body: some View {
    print("? [3] redrawing...")
    return VStack {
      Text("Page 3")
          .padding()
      NavigationLink(destination: Page4(isActive: $env.isPage4Active)
                      .environmentObject(env),
                     isActive: $env.isPage4Active) {
        EmptyView()
      }.isDetailLink(true)
      Button(action: {
        print("ikaw??")
        env.isPage3Active = false
      }, label: {
        Text("Back")
      })
        .padding()
      Button(action: {
        env.isPage4Active = true
      }, label: {
        Text("Next")
      })
    }
    .navigationBarBackButtonHidden(true)
    .onAppear {
      print("? ============================================  >>>> ")
      print("? [3] appeared")
    }
    .onDisappear {
      print("? [3] disappear")
      print("? <<<<  ============================================ ")
    }
  }
}

struct Page4: View {
  @Binding var isActive: Bool
  @State private var isDetailActive = false
  @EnvironmentObject var env: GlobalEnviroment

  var body: some View {
    print("? [4] redrawing...")
    return VStack {
      Text("Page 4")
          .padding()
      NavigationLink(destination: Page5(isActive: $env.isPage5Active)
                      .environmentObject(env),
                     isActive: $env.isPage5Active) {
        EmptyView()
      }.isDetailLink(true)
      Button(action: {
        env.isPage4Active = false
      }, label: {
        Text("Back")
      })
        .padding()
      Button(action: {
        env.isPage5Active = true
      }, label: {
        Text("Next")
      })
    }
    .navigationBarBackButtonHidden(true)
    .onAppear {
      print("? ============================================  >>>> ")
      print("? [4] appeared")
    }
    .onDisappear {
      print("? [4] disappear")
      print("? <<<<  ============================================ ")
    }
  }
}

struct Page5: View {
  @Binding var isActive: Bool
  @EnvironmentObject var env: GlobalEnviroment

  var body: some View {
    print("? [5] redrawing...")
    return VStack {
      Spacer()
      Button(action: {
        env.isPage5Active = false
      }, label: {
        Text("Back")
      })
        .padding()
      Text("Page 5")
          .padding()
      Spacer()
    }
    .navigationBarBackButtonHidden(true)
    .onAppear {
      print("? ============================================  >>>> ")
      print("? [5] appeared")
    }
    .onDisappear {
      print("? [5] disappear")
      print("? <<<<  ============================================ ")
    }
  }
}

1 个答案:

答案 0 :(得分:0)

@Binding 在深度嵌套的视图中似乎不可靠,尤其是在 5 级层次结构中。

看起来 isActive 参数在多个嵌套视图中也不可靠。

一种可能的解决方法是使用 @Environment(\.presentationMode) - 这样即使 Binding 被重置,您仍然可以转到上一个视图:

struct Page4: View {
  @Environment(\.presentationMode) private var presentationMode // add this
  @EnvironmentObject var env: GlobalEnviroment

  var body: some View {
    print("? [4] redrawing...")
    return VStack {
      Text("Page 4")
          .padding()
      NavigationLink(destination: Page5()
                      .environmentObject(env),
                     isActive: $env.isPage5Active) {
        EmptyView()
      }.isDetailLink(true)
      Button(action: {
        env.isPage4Active = false
        presentationMode.wrappedValue.dismiss() // dismiss to go to the previous view
      }, label: {
        Text("Back")
      })
        .padding()
      Button(action: {
        env.isPage5Active = true
      }, label: {
        Text("Next")
      })
    }
    .navigationBarBackButtonHidden(true)
    .onAppear {
      print("? ============================================  >>>> ")
      print("? [4] appeared")
    }
    .onDisappear {
      print("? [4] disappear")
      print("? <<<<  ============================================ ")
    }
  }
}

(仅针对一个视图添加,但显然它应该在每个视图的 dismiss 操作中)。