SwiftUI - 计时器到期后的选择器视图未按预期工作 - 似乎具有脉动效果

SwiftUI - picker view after timer expires not working as expected-seems to have a pulsating effect

我正在构建一个非常简单的计时器应用程序,我想要它做的是在计时器到期后显示一个选择器视图以添加更多时间并返回到计时器。然而,虽然它编译了,但它给了我一个非常奇怪的功能,如下所示。

我相信 secondView 结构是这里的罪魁祸首,但我不确定确切的问题。代码附在下面:

import SwiftUI

struct ContentView: View {
    @State var secondScreenShown = false
    @State var timerVal = 1
    
    var body: some View {
        VStack{
            Picker(selection: $timerVal, label: Text("Set Half Time")) {
                Text("1").tag(60)
                Text("2").tag(120)
                Text("20").tag(1200)
                Text("25").tag(1500)
                Text("30").tag(1800)
                Text("35").tag(2100)
                Text("40").tag(2400)
                Text("45").tag(2700)
                
            }
            NavigationLink(destination: SecondView(secondScreenShown: $secondScreenShown, timerVal: timerVal), isActive: $secondScreenShown) {
                Text("Set Half!")
            }
        }
    }
}
struct SecondView: View {
    @Binding var secondScreenShown: Bool
    @State var timerVal: Int
    
    var body: some View {
            VStack{
                if timerVal > 0 {
                    Text("Time Remaining in Half")
                        .font(.system(size: 14))
                    HStack(spacing: 33){
                        Text("\(timerVal / 60)")
                            .font(.system(size: 40))
                        Text("\(timerVal % 60)")
                            .font(.system(size: 40))
                            .onAppear(){
                                Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in
                                    if self.timerVal > 0 {
                                        self.timerVal -= 1
                                    }
                                }
                            }
                        
                    }
                    HStack{
                        Text("Minutes")
                            .font(.system(size: 14))
                        Text("seconds")
                            .font(.system(size: 14))
                    }
                    Button(action: {
                        self.secondScreenShown = false
                    }) {
                        Text("Cancel")
                            .foregroundColor(.red)
                    }
    
                } else {
                    // This is the code I believe has the error
                    VStack{
                        Picker(selection: $timerVal, label: Text("Add Stoppage Time?")) {
                            Text("1").tag(60)
                            Text("2").tag(120)
                            Text("3").tag(180)
                            Text("4").tag(240)
                            Text("5").tag(300)
                            Text("6").tag(360)
                            Text("7").tag(420)
                            Text("8").tag(480)
                            Text("9").tag(540)
                        }
                        NavigationLink(destination: SecondView(secondScreenShown: $secondScreenShown, timerVal: timerVal), isActive: $secondScreenShown) {
                            Text("Add Stoppage")
                                .foregroundColor(.green)
                        }
                        Button(action: {
                            self.secondScreenShown = false
                        }) {
                            Text("Done")
                                .foregroundColor(.red)
                        }
                        
                    }
                    
            }

            }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        Group {
            ContentView()
            ContentView()
        }
    }
}

你能帮帮我吗?

您的问题是您还使用 secondScreenShown 来显示第三个屏幕。由于该值为 true,它会自动采用 link,并且您会不断推送其他屏幕。

您真的不需要再推一个屏幕。如果 Add Stoppage 只更新时间就足够了,但是选择器需要使用一个新变量,以便在按下按钮之前它不会更新 timerVal

我添加了另一个名为 @State var overtime: Bool 的状态变量。这用于避免每次计时器达到零时重复显示 Add Stoppage

此外,当 Timer 达到 0 时,您应该 .invalidate() 以便它可以被释放,并且您不会以多个计时器结束 运行。

这是更新后的代码:

import SwiftUI

struct ContentView: View {
    @State var secondScreenShown = false
    @State var timerVal = 60
    
    var body: some View {
        VStack{
            Picker(selection: $timerVal, label: Text("Set Half Time")) {
                Text("1").tag(60)
                Text("2").tag(120)
                Text("20").tag(1200)
                Text("25").tag(1500)
                Text("30").tag(1800)
                Text("35").tag(2100)
                Text("40").tag(2400)
                Text("45").tag(2700)
                
            }
            NavigationLink(destination: SecondView(secondScreenShown: $secondScreenShown, timerVal: timerVal), isActive: $secondScreenShown) {
                Text("Set Half!")
            }
        }
    }
}
struct SecondView: View {
    @Binding var secondScreenShown: Bool
    @State var timerVal: Int
    @State var stoppage: Int = 60
    @State var overtime: Bool = false
    
    var body: some View {
            VStack{
                if timerVal > 0 || overtime {
                    Text("Time Remaining in Half")
                        .font(.system(size: 14))
                    HStack(spacing: 33){
                        Text("\(timerVal / 60)")
                            .font(.system(size: 40))
                        Text("\(timerVal % 60)")
                            .font(.system(size: 40))
                            .onAppear(){
                                Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { tim in
                                    if self.timerVal > 0 {
                                        self.timerVal -= 1
                                        if self.timerVal == 0 {
                                            tim.invalidate()
                                        }
                                    }
                                }
                            }
                        
                    }
                    HStack{
                        Text("Minutes")
                            .font(.system(size: 14))
                        Text("seconds")
                            .font(.system(size: 14))
                    }
                    Button(action: {
                        self.secondScreenShown = false
                    }) {
                        Text("Cancel")
                            .foregroundColor(.red)
                    }
    
                } else {
                    // This is the code I believe has the error
                    VStack{
                        Picker(selection: $stoppage, label: Text("Add Stoppage Time?")) {
                            Text("1").tag(60)
                            Text("2").tag(120)
                            Text("3").tag(180)
                            Text("4").tag(240)
                            Text("5").tag(300)
                            Text("6").tag(360)
                            Text("7").tag(420)
                            Text("8").tag(480)
                            Text("9").tag(540)
                        }
                        Button(action: {
                            self.timerVal = self.stoppage
                            self.overtime = true
                        }) {
                            Text("Add Stoppage")
                                .foregroundColor(.green)
                        }
                        Button(action: {
                            self.secondScreenShown = false
                        }) {
                            Text("Done")
                                .foregroundColor(.red)
                        }
                        
                    }
                    
            }

            }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        Group {
            ContentView()
            ContentView()
        }
    }
}