|
title says it all. Right now, the alert is covering up the animations I've so carefully crafted. How can I get the alert to wait a second before showing?
|
|
Hey Now seeks advice for delaying code execution:
how can I make the alert wait for the animations to finish?
This hint might be useful?
See -> Rooster's Delay function
Wait?! Is it pronouced "Hey Now?" or "Hal No?"
|
|
How I would approach:
- Use a timer
- Timer starts when your criteria for the alert is met
- When timer reaches the time duration of your animation you trigger you boolean alert value
- Stop/reset timer
- Alert pops up
:)
I am sure there is a more sophisticated way, but this what I thought for now..
|
|
@Obelix -- thanks for the help. I take it the answer is, "Answer non-trivial, ask again later when we get to concurrency."
Originally I was @haineux, which is the French word for "Heinous" ("horrible and evil") for silly reasons. "Haineux" is pronounced "Hey No" in French.
|
|
@ioannisfa Not quite figuring it out. Here's my code:
import SwiftUI
struct ContentView: View {
@State private var countries = ["Estonia", "France", "Germany", "Ireland", "Italy", "Nigeria", "Poland", "Russia", "Spain", "UK", "US"].shuffled()
@State private var correctAnswer = Int.random(in: 0...2)
@State private var showingScore = false
@State private var scoreTitle = ""
@State private var attempts = 0
@State private var correct = 0
@State private var selectedFlag = -1
@State private var hasTimeElapsed = false
var body: some View {
ZStack {
LinearGradient(gradient: Gradient(colors: [.blue, .gray]), startPoint: .top, endPoint: .bottom)
.ignoresSafeArea()
VStack(spacing: 30) {
VStack {
Text("Tap the flag of")
.foregroundColor(.white)
.font(.subheadline.weight(.heavy))
Text(countries[correctAnswer])
.foregroundColor(.white)
.font(.largeTitle.weight(.semibold))
}
ForEach(0..<3) { number in
Button {
flagTapped(number)
} label: {
Image(countries[number])
}
.clipShape(RoundedRectangle(cornerRadius: 20))
.shadow(radius: 10, x:5, y:5)
.rotation3DEffect(.degrees(selectedFlag == number ? 360 : 0), axis: (x: 0, y: 1, z: 0))
.opacity(((selectedFlag == number) || (selectedFlag == -1)) ? 1 : 0.3)
.scaleEffect((selectedFlag == -1) ? 1 : ((selectedFlag == number) ? 1.25 : 0.5))
.animation(.default, value: selectedFlag)
}
}
.alert(scoreTitle, isPresented:$showingScore) {
Button("Continue", action: askQuestion)
} message: {
Text("Your score is \(correct) out of \(attempts)")
}
}
}
func askQuestion() {
countries.shuffle()
correctAnswer = Int.random(in: 0...2)
selectedFlag = -1
hasTimeElapsed = false
}
func flagTapped(_ number: Int) {
selectedFlag = number
attempts += 1
if number == correctAnswer {
scoreTitle = "Correct"
correct += 1
} else {
scoreTitle = "Wrong"
}
showingScore = true
}
private func delay() async {
// Delay of 1 seconds (1 second = 1_000_000_000 nanoseconds)
try? await Task.sleep(nanoseconds: 1_000_000_000)
hasTimeElapsed = true
}
}
|
|
I like Rooster's delay function. When I did this challenge I used google to get the answer I used.
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
showingScore = true}
I don't know if it's the right way or best practice, but it worked for me.
|
|
@WileECodee I like your solution a lot. I come from AppKit, so it's obvious in retrospect, ughhhhhh.
|
|
Late to the show, but I wanted to do the same thing, and I ended up using the following code to make it work.
Update flagTapped(_ number: Int) method by replacing showingScore = true with
Task {
try? await Task.sleep(nanoseconds: 1_000_000_000)
await MainActor.run {
showingScore = true
}
}
I actually learned this today from the following article: Main Actor
Task will allow us to run the code in the background, sleep for x amount of seconds, then MainActor will ensure the next code runs on the UI thread.
|
|
@daffyduck Thank you very many of this code snippet. I tried to found this kind of easy solution for delaying Alert. Have to check also that Main Actor infopage.
|