|
I tried to add the animation in the first challenge of Project 6, but it always comes after the next question. Is there a way to make the correct flag rotates before flagTapped method run?
|
|
Can you share your code, so we could help more specifically
|
|
Thank you @Sangsom for your reply, I solved the issue using:
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {self.askQuestion()}
and this is my code:
struct ImageModifier: ViewModifier{
func body(content: Content) -> some View {
content
.clipShape(Capsule())
//.overlay(Capsule().stroke(Color.black, lineWidth: 1))
//.shadow(color: .black, radius: 2)
}
}
struct LargeRed: ViewModifier {
func body(content: Content) -> some View{
content
.font(.largeTitle)
.foregroundColor(.red)
.frame(width: UIScreen.main.bounds.width)
}
}
extension View{
func largeRed() -> some View {
self.modifier(LargeRed())
}
func imageModifier() -> some View {
self.modifier(ImageModifier())
}
}
struct ContentView: View {
@State private var countries = ["Estonia", "France", "Germany", "Ireland", "Italy", "Nigeria", "Poland", "Russia", "Spain", "UK", "US"]
@State private var correctAnswer = Int.random(in: 0...2)
@State private var showingScore = false
@State private var score = 0
@State private var userTapped = 0
@State private var animationAmount = 0.0
@State private var opacity = 1.0
@State private var offset = CGFloat.zero
@State private var disabled = false
var body: some View {
ZStack{
LinearGradient(gradient: Gradient(colors: [.blue, .black]), startPoint: .top, endPoint: .bottom).edgesIgnoringSafeArea(.all)
VStack(spacing: 30){
VStack(spacing: 30) {
Text("Tap the flag of")
.foregroundColor(.white)
.padding(.top, 50)
.font(.largeTitle)
Text(countries[correctAnswer])
.largeRed()
}
Spacer()
ForEach(0 ..< 3) { number in
Button(action: {
if number == self.correctAnswer {
self.flagTapped(number)
self.userTapped = number
withAnimation(.easeInOut(duration: 2)) {
self.animationAmount += 360
self.opacity -= 0.75
}
DispatchQueue.main.asyncAfter(deadline: .now() + 2)
{self.askQuestion()}
} else {
self.flagTapped(number)
self.userTapped = number
withAnimation(.easeInOut(duration: 0.5)) {
self.offset = 200
}
}
self.disabled = true
}) {
Image(self.countries[number])
.renderingMode(.original)
.imageModifier()
}
.rotation3DEffect(.degrees(self.animationAmount), axis: (x: 0, y: number == self.userTapped ? 1 : 0, z: 0))
.offset(x: number != self.correctAnswer ? self.offset : .zero, y: .zero)
.clipped()
.opacity(number != self.userTapped ? self.opacity : 1.0)
.disabled(self.disabled)
}
Spacer()
ZStack{
Color.red
.clipShape(Circle())
.frame(width: 150, height: 100)
Text("\(score)")
}
.foregroundColor(.white)
.font(.largeTitle)
}
}
.alert(isPresented: $showingScore) {
Alert(title: Text("Wrong"), message: Text("This is the flag of \(countries[userTapped])"), dismissButton: .default(Text("Continue")){
self.askQuestion()
})
}
}
func flagTapped (_ number: Int){
if number == correctAnswer{
score += 1
} else{
showingScore = true
}
}
func askQuestion(){
self.disabled = false
self.opacity = 1
self.offset = .zero
countries.shuffle()
correctAnswer = Int.random(in: 0...2)
}
}
|
|
Probably spent more time than I should have on this, but I learned a lot. Here is an implementation I came up with... (revised)
import SwiftUI
enum AnswerStatus {
case unanswered, correct, incorrect
}
struct ContentView: View {
let animationTime = 0.25
let affirmations = ["Way To Go!", "You Got It!", "Oh Yeah!", "Damn Straight!", "Nailed It!", "Boo-yah!"].shuffled()
let encouragements = ["Darn!", "Try again!", "So close!", "Almost!", "Shoot!", "Next time!"].shuffled()
@State private var numCorrect = 0
@State private var numIncorrect = 0
@State private var countries = ["Estonia", "France", "Germany", "Ireland", "Italy", "Nigeria", "Poland", "Russia", "Spain", "UK", "US" ].shuffled()
@State private var correctAnswerNum = Int.random(in: 0...2)
@State private var answerStatus = AnswerStatus.unanswered
@State private var tappedNum = 0
@State private var message = Array("")
@State private var animationInterval = 0.0
var body: some View {
ZStack {
LinearGradient(gradient:
Gradient(colors: [.blue, .black]), startPoint: .top, endPoint: .bottom)
.edgesIgnoringSafeArea(.all)
VStack (spacing: 30) {
VStack {
Text("Tap the flag of")
.foregroundColor(.white)
Text(countries[correctAnswerNum])
.foregroundColor(.white)
.font(.largeTitle)
.fontWeight(.black)
}
ForEach(0..<3) { number in
Button(action: {
withAnimation(.linear(duration: self.animationTime)) {
self.flagTapped(number)
}
}) {
Image(self.countries[number])
.renderingMode(.original)
}
.clipShape(Capsule())
.overlay(Capsule().stroke(Color.black, lineWidth: 1))
.shadow(color: .black, radius: 2)
.rotation3DEffect(.degrees(self.answerStatus == AnswerStatus.correct && self.tappedNum == number ? 360 : 0), axis: (x: 0, y: 1, z: 0))
.opacity(self.answerStatus != AnswerStatus.unanswered && self.tappedNum != number ? 0.25 : 1.0)
.disabled(self.answerStatus != AnswerStatus.unanswered)
}
VStack (alignment: .leading) {
Text("Number correct: \(numCorrect)")
.foregroundColor(.white)
Text("Number incorrect: \(numIncorrect)")
.foregroundColor(.white)
}
Spacer()
}
VStack {
Spacer()
HStack(spacing: 0) {
ForEach(0 ..< self.message.count, id: \.self) { num in
Text(String(self.message[num]))
.foregroundColor(self.answerStatus == AnswerStatus.correct ? Color.green : Color.red)
.font(.title)
.fontWeight(.black)
.padding(1)
.transition(AnyTransition.asymmetric(
insertion: AnyTransition.opacity.animation(Animation.easeIn.delay(Double(num) * self.animationInterval)),
removal: AnyTransition.opacity.animation(Animation.easeOut))
)
}
}
}
}
}
func flagTapped(_ number: Int) {
self.tappedNum = number
if correctAnswerNum == number {
numCorrect += 1
self.answerStatus = AnswerStatus.correct
self.message = Array(affirmations[Int.random(in: 0 ..< affirmations.count)])
self.animationInterval = animationTime / Double(self.message.count)
DispatchQueue.main.asyncAfter(deadline: .now() + animationTime + 1) {
self.askQuestion(true)
}
} else {
numIncorrect += 1
answerStatus = AnswerStatus.incorrect
self.message = Array(encouragements[Int.random(in: 0 ..< encouragements.count)])
self.animationInterval = animationTime / Double(self.message.count)
DispatchQueue.main.asyncAfter(deadline: .now() + animationTime + 1) {
self.askQuestion(false)
}
}
}
func askQuestion(_ advanceToNext: Bool) {
if advanceToNext {
countries.shuffle()
correctAnswerNum = Int.random(in: 0...2)
}
answerStatus = AnswerStatus.unanswered
message = Array("")
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
|
|
Hey guys, on the same topic, i am having problem rotating only the right selected one. I get to rotate all the flags at the same time. Any help?
code:
struct ContentView: View {
@State private var countries = ["Estonia", "France", "Germany", "Ireland", "Italy", "Monaco", "Nigeria", "Poland", "Russia", "Spain", "UK", "US" ].shuffled()
@State private var correctAnswer = Int.random(in: 0...2)
@State private var scoreTitle = ""
@State private var score: Int = 0
@State private var animationAmount = 0.0
var body: some View {
ZStack {
LinearGradient(gradient: Gradient(colors: [.blue,.black]), startPoint: .top, endPoint: .bottom)
.edgesIgnoringSafeArea(.all)
VStack(spacing:30){
VStack{
Text("Tap the flag of")
.foregroundColor(.white)
//name of the Country:
Text(countries[correctAnswer])
.foregroundColor(.white)
.font(.largeTitle)
.fontWeight(.black)
}
ForEach(0..<3) { number in
Button(action: {
self.flagTapped(number)
}) {
Image(self.countries[number])
.renderingMode(.original)
.clipShape(Capsule())
.overlay(Capsule().stroke(Color.black, lineWidth:1 ))
.shadow(color: .black, radius: 20)
}
.rotation3DEffect(.degrees(self.animationAmount), axis: (x:0,y:1,z:0))
.animation(.easeInOut(duration: 2))
}
VStack {
Text("Your score is:")
.foregroundColor(.white)
Text(String(score))
.foregroundColor(.white)
}
Spacer()
}
}
func flagTapped(_ number: Int) {
if number == correctAnswer {
scoreTitle = "Correct"
self.score += 1
animationAmount += 360
} else {
scoreTitle = "Wrong, that is the flag of \(countries[number])"
}
}
|
|
Is there an answer to this question? I have the same problem.
|
|
I got it! The y: parameter should be
number == self.correctAnswer ? 1 : 0
|
|
I got the correct flag to rotate when selected by using a custom view (i.e. Flag Image) that implemented the 3D rotation on the flag that was correct
|
|
Hi,
I had a look at the proposed solutions, but I am not quite getting it. How do I delay an alert, such that the animation shows first? I am not seeing the rotation unfortunately.
Here is my code:
struct FlagImage : View {
var imageName : String
var body: some View {
Image(imageName)
.renderingMode(.original)
.clipShape(Capsule())
.overlay(Capsule().stroke(Color.black, lineWidth: 1))
.shadow(color: .black, radius: 2)
}
}
struct ContentView: View {
@State private var countries = ["Estonia", "France", "Germany", "Ireland", "Italy", "Nigeria", "Poland", "Russia", "Spain", "UK", "US"].shuffled()
@State var correctAnswer = Int.random(in: 0...2)
@State private var showingScore = false
@State private var scoreTitle = ""
@State private var score = 0
@State private var rotationAmount = 0.0
@State private var tapped = false
var body: some View {
ZStack{
LinearGradient(gradient: Gradient(colors: [.blue, .black]), startPoint: .top, endPoint: .bottom).edgesIgnoringSafeArea(.all)
VStack(spacing: 30){
VStack {
Text("Tap the flag of")
.foregroundColor(.white)
Text(countries[correctAnswer])
.foregroundColor(.white)
.font(.largeTitle)
.fontWeight(.black)
}
ForEach(0 ..< 3) { number in Button(action: {
self.tapped.toggle()
self.flagTapped(number)
}) {
FlagImage(imageName: self.countries[number])
.rotation3DEffect(.degrees(self.rotationAmount), axis: (x: 0, y: (number == self.correctAnswer && self.tapped) ? 1 : 0, z: 0))
.opacity((number != self.correctAnswer && self.tapped) ? 0.25 : 1)
}
}
Text("Your score is \(score)")
.foregroundColor(.white)
Spacer()
}
}
.alert(isPresented: $showingScore) {
Alert(title: Text(scoreTitle), message: Text("Your score is \(score)"), dismissButton: .default(Text("Continue")) {self.askQuestion()
})
}
}
func flagTapped(_ number: Int) {
if number == correctAnswer {
scoreTitle = "Correct"
score+=1
} else {
scoreTitle = "Wrong, that's the flag of \(countries[number])"
if score > 0{
score-=1
}
}
showingScore = true
}
func askQuestion() {
tapped.toggle()
countries.shuffle()
correctAnswer = Int.random(in: 0...2)
}
}
|