I'm building a very simple timer app, and what I want it to do is that I want to show a picker view once the timer expires to add more time and go back to the timer. However, although it compiles, it gives me a really weird functionality shown below.
I do believe the secondView
struct is the culprit here, but I'm not sure the exact problem. The code is attached below:
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()
}
}
}
Can you help me?
CodePudding user response:
Your issue is that you are using secondScreenShown
to show the third screen as well. Since that value is true
, it automatically takes the link and you continuously push additional screens.
You don't really need to push another screen. It is enough if the Add Stoppage just updates the time, but the picker needs to use a new variable so that it doesn't update timerVal
until the button is pressed.
I added another state var called @State var overtime: Bool
. This is used to avoid repeatedly showing the Add Stoppage every time the timer reaches zero.
Also, you should .invalidate()
the Timer
when it reaches 0 so that it can be freed and you don't end up with multiple timers running.
Here is the updated code:
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()
}
}
}