带PresentationMode的SwiftUI NavigationView在多级导航层次结构中创建错误
我有一个iOS 13.5 SwiftUI(macOS 10.15.6)应用程序,它要求用户在带PresentationMode的SwiftUI NavigationView在多级导航层次结构中创建错误,swiftui,swiftui-navigationlink,swiftui-environment,Swiftui,Swiftui Navigationlink,Swiftui Environment,我有一个iOS 13.5 SwiftUI(macOS 10.15.6)应用程序,它要求用户在NavigationView层次结构中导航两层才能玩游戏。比赛是定时的。我想在两个级别中都使用自定义后退按钮,但如果我这样做,第二个级别中的计时器会以一种奇怪的方式中断。如果我在第一级放弃自定义后退按钮,使用系统后退按钮,一切都会正常工作。下面是一个复制问题的最小应用程序: class SimpleTimerManager: ObservableObject { @Published var elap
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)
}
}
类SimpleTimeManager:ObserveObject{
@已发布变量elapsedSeconds:Double=0.0
专用(设置)变量计时器=计时器()
func start(){
打印(“计时器启动”)
timer=timer.scheduledTimer(withTimeInterval:0.01,repeats:true){in
如果(Int(self.elapsedsons*100)%100==0){print(\(self.elapsedsons)}
self.elapsedSeconds+=0.01
}
}
函数停止(){
timer.invalidate()
elapsedSeconds=0.0
打印(“计时器停止”)
}
}
结构ContentView:View{
var body:一些观点{
导航视图{
导航链接(目标:CountDownIntervalPassThroughView()){
文本(“启动计时器!”)
}
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
结构倒计时间隔passthroughview:视图{
@环境(\.presentationMode)变量模式:绑定
var body:一些观点{
VStack{
导航链接(目标:CountDownIntervalView()){
文本(“再次单击…”)
}
按钮(操作:{
self.mode.wrappedValue.disclose()文件
打印(“从倒计时间隔返回通过视图”)
}) {
文本(“返回!”)
}
}
.navigationBarBackButtonHidden(真)
}
}
结构倒计时IntervalView:视图{
@ObservedObject var timerManager=SimpleTimerManager()
@环境(\.presentationMode)变量模式:绑定
变量间隔:双精度{10.0-self.timermager.elapsedsons}
var body:一些观点{
VStack{
文本(“剩余时间:\(字符串(格式:%.2f”,间隔)))
.onReceive(timerManager.$elapsedSeconds){in
打印(“\(self.interval)”)
如果self.interval在Xcode 12/iOS 14上没有什么奇怪的是的,在iOS 14模拟器上测试过。我仍然使用11/13.5。再戳一戳,我会看到两个奇怪的行为。如果我不使用传递,一切都可以手动点击。但是如果我让计时器过期并创建一个弹出窗口,当我尝试重新启动它时,视图会立即弹出,但e timer一直在运行。如果我确实使用了pass-through,那么当我向下导航两层时计时器就会启动,但是视图不会更新。我想知道这是否是SwiftUI处理onAppear
和模式时的一个错误。请关闭方法。一般来说,onAppear
和onDisappear
看起来超级脆弱,它们不会触发e您期望或完成其关闭的方式等。