首页 > 解决方案 > 带有 PresentationMode 的 SwiftUI NavigationView 在多级导航层次结构中创建错误

问题描述

我有一个 iOS 13.5 SwiftUI (macOS 10.15.6) 应用程序,它需要用户在NavigationView层次结构中导航两个级别才能玩游戏。比赛计时。我想在两个级别都使用自定义后退按钮,但如果我这样做了,第二级的计时器会以一种奇怪的方式中断。如果我放弃第一级的自定义后退按钮并使用系统后退按钮一切正常。这是一个复制问题的最小应用程序:

class SimpleTimerManager: ObservableObject {
  @Published var elapsedSeconds: Double = 0.0
  private(set) var timer = Timer()
  
  func start() {
    print("timer started")
    timer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true) {_ in
      if (Int(self.elapsedSeconds * 100) % 100 == 0) { print ("\(self.elapsedSeconds)") }
      self.elapsedSeconds += 0.01
    }
  }
  
  func stop() {
    timer.invalidate()
    elapsedSeconds = 0.0
    print("timer stopped")
  }
}

struct ContentView: View {
  var body: some View {
    NavigationView {
      NavigationLink(destination: CountDownIntervalPassThroughView()) {
        Text("Start the timer!")
      }
    }
    .navigationViewStyle(StackNavigationViewStyle())
  }
}

struct CountDownIntervalPassThroughView: View {
  @Environment(\.presentationMode) var mode: Binding<PresentationMode>

  var body: some View {
    VStack {
      NavigationLink(destination: CountDownIntervalView()) {
        Text("One more click...")
      }
      Button(action: {
        self.mode.wrappedValue.dismiss()
        print("Going back from CountDownIntervalPassThroughView")
      }) {
        Text("Go back!")
      }
    }
    .navigationBarBackButtonHidden(true)
  }
}

struct CountDownIntervalView: View {
  @ObservedObject var timerManager = SimpleTimerManager()
  @Environment(\.presentationMode) var mode: Binding<PresentationMode>
  var interval: Double { 10.0 - self.timerManager.elapsedSeconds }
    
  var body: some View {
    VStack {
      Text("Time remaining: \(String(format: "%.2f", interval))")
        .onReceive(timerManager.$elapsedSeconds) { _ in
          print("\(self.interval)")
          if self.interval <= 0 {
            print("timer auto stop")
            self.timerManager.stop()
            self.mode.wrappedValue.dismiss()
          }
      }
      Button(action: {
        print("timer manual stop")
        self.timerManager.stop()
        self.mode.wrappedValue.dismiss()
      }) {
        Text("Quit early!")
      }
    }
    .onAppear(perform: {
      self.timerManager.start()
    })
    .navigationBarBackButtonHidden(true)
  }
}

实际上,使用此示例代码,即使我重新使用系统也会出现一些奇怪的行为,尽管我的完整应用程序没有这个问题,而且我看不出任何可以解释原因的差异。但是 - 目前我想关注为什么这段代码会因多级自定义后退按钮而中断。

在此先感谢您对此的任何想法...

标签: swiftuiswiftui-navigationlinkswiftui-environment

解决方案


推荐阅读