在尝试为这些按钮设置动画之后,我放弃了并寻求帮助。 我只想为正确的按钮设置动画,如下所示: .rotation3DEffect(.degrees(self.animationAmount),轴:(x:0,y:1,z:0)) 并同时使其他两个按钮淡出25%。
当玩家单击错误的按钮时,我想 为错误的按钮设置动画,如下所示: .rotation3DEffect(.degrees(self.animationAmount),轴:(x:1,y:1,z:1))(或您认为可能会导致灾难的其他方式),而另两个则不予考虑。
在那之后,我希望警报显示。
下面是我的代码。我评论了我想做什么以及在可能的情况下。 一切都按我想要的方式工作,但动画无法播放。
非常感谢您的帮助
import SwiftUI
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 scoreTitle = ""
@State private var userScore = 0
@State private var userTapped = ""
@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: 20) {
VStack {
Text("Tap the flag of...")
.foregroundColor(.white).font(.title)
Text(countries[correctAnswer])
.foregroundColor(.white)
.font(.largeTitle).fontWeight(.black)
}
ForEach(0 ..< 3) { number in
Button(action: {
self.flagTapped(number)
if self.correctAnswer == number {
//animate the correct button only like this:
//.rotation3DEffect(.degrees(self.animationAmount), axis: (x: 0, y: 1, z: 0))
// and
// make the other two buttons fade out to 25% opacity
} else {
// animate the wrong button like this:
//.rotation3DEffect(.degrees(self.animationAmount), axis: (x: 1, y: 1, z: 1))
}
}) {
Image(self.countries[number])
.renderingMode(.original)
.clipShape(Capsule())
.overlay(Capsule().stroke(Color .black, lineWidth: 1))
.shadow(color: .black, radius: 2)
}
}
Text ("your score is:\n \(userScore)").foregroundColor(.white).font(.title).multilineTextAlignment(.center)
}
}
.alert(isPresented: $showingScore) {
Alert(title: Text(scoreTitle), message: Text("You chose the flag of \(userTapped)\nYour score is now: \(userScore)"), dismissButton: .default(Text("Continue")) {
self.askQuestion()
})
}
}
func flagTapped(_ number: Int) {
userTapped = countries[number]
if number == correctAnswer {
scoreTitle = "Correct"
userScore += 1
} else {
scoreTitle = "Wrong"
userScore -= 1
}
showingScore = true
}
func askQuestion() {
countries.shuffle()
correctAnswer = Int.random(in: 0...2)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
答案 0 :(得分:1)
在解决此挑战时,我遇到了与您类似的问题。我想出了不使用DispatchQueue.main.asyncAfter
的解决方案。我提出以下作为最终解决方案:
这是完整的解决方案(我对实现上述解决方案至关重要的部分发表评论):
import SwiftUI
// Create a custom view
struct FlagImage: View {
var countryFlags: String
var body: some View {
Image(countryFlags)
.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 private var correctAnswer = Int.random(in: 0...3)
@State private var showingScore = false
@State private var scoreTitle = ""
@State private var userScore = 0
// Properties for animating the chosen flag
@State private var animateCorrect = 0.0
@State private var animateOpacity = 1.0
@State private var besidesTheCorrect = false
@State private var besidesTheWrong = false
@State private var selectedFlag = 0
var body: some View {
ZStack {
LinearGradient(gradient: Gradient(colors: [.blue, .black]), startPoint: .top, endPoint: .bottom).edgesIgnoringSafeArea(.all)
VStack(spacing: 30) {
VStack {
Text("Tap on the flag!")
.foregroundColor(.white)
.font(.title)
Text(countries[correctAnswer])
.foregroundColor(.white)
.font(.largeTitle)
.fontWeight(.black)
}
ForEach(0 ..< 4) { number in
Button(action: {
self.selectedFlag = number
self.flagTapped(number)
}) {
FlagImage(countryFlags: self.countries[number])
}
// Animate the flag when the user tap the correct one:
// Rotate the correct flag
.rotation3DEffect(.degrees(number == self.correctAnswer ? self.animateCorrect : 0), axis: (x: 0, y: 1, z: 0))
// Reduce opacity of the other flags to 25%
.opacity(number != self.correctAnswer && self.besidesTheCorrect ? self.animateOpacity : 1)
// Animate the flag when the user tap the wrong one:
// Create a red background to the wrong flag
.background(self.besidesTheWrong && self.selectedFlag == number ? Capsule(style: .circular).fill(Color.red).blur(radius: 30) : Capsule(style: .circular).fill(Color.clear).blur(radius: 0))
// Reduce opacity of the other flags to 25% (including the correct one)
.opacity(self.besidesTheWrong && self.selectedFlag != number ? self.animateOpacity : 1)
}
Spacer()
Text("Your total score is: \(userScore)")
.foregroundColor(Color.white)
.font(.title)
.fontWeight(.black)
Spacer()
}
}
.alert(isPresented: $showingScore) {
Alert(title: Text(scoreTitle), dismissButton: .default(Text("Continue")) {
self.askQuestion()
})
}
}
func flagTapped(_ number: Int) {
if number == correctAnswer {
scoreTitle = "Correct!"
userScore += 1
// Create animation for the correct answer
withAnimation {
self.animateCorrect += 360
self.animateOpacity = 0.25
self.besidesTheCorrect = true
}
} else {
scoreTitle = "Wrong!"
// Create animation for the wrong answer
withAnimation {
self.animateOpacity = 0.25
self.besidesTheWrong = true
}
}
showingScore = true
}
func askQuestion() {
// Return the booleans to false
besidesTheCorrect = false
besidesTheWrong = false
countries = countries.shuffled()
correctAnswer = Int.random(in: 0...3)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
基本上,我的解决方案是在“按钮”视图之后的视图修饰符(例如.rotation3DEffect(...)
,.opacity(...)
和.background(...)
)内添加三元运算符。棘手的部分是正确组合检查条件。
我更喜欢在withAnimation
函数中添加flagTapped
修饰符。如果用户选择正确或错误的标志,在这个地方我可以更好地控制动画。
我对原始挑战进行了小的更改:只需在视图中再添加一个标志。
用户按下正确和错误的标志时的最终结果是:
。
答案 1 :(得分:0)
我有同样的问题。这是我的解决方案(仅与您的代码不同):
ForEach:
ForEach(0 ..< 3, id: \.self){ number in
Button(action: {
withAnimation{
self.tappedFlag = number
self.flagTapped(number)
}
}){
FlagImage(imageName: self.countries[number])
}
.rotation3DEffect(.degrees(self.isCorrect && self.selcectedNumber == number ? 360 : 0), axis: (x: 0, y: 1, z: 0))
.opacity(self.isFadeOutOpacity && self.selcectedNumber != number ? 0.25 : 1)
.rotation3DEffect(.degrees(self.wrongAnswer && number != self.correctAnswer ? 180 : 0), axis: (x: 1, y: 0, z: 0))
.opacity(self.wrongAnswer && number != self.correctAnswer ? 0.25 : 1)
}
警报:
.alert(isPresented: $showingScore){
if scoreTitle == "Correct"{
return Alert(title: Text(scoreTitle), message: Text("Your score is \(userScore)"), dismissButton: .default(Text("Continue")){
self.askQuestion()
})
}else{
return Alert(title: Text(scoreTitle), message: Text("That is the flag of \(countries[tappedFlag]), you lost one point!"), dismissButton: .default(Text("Continue")){
self.askQuestion()
})
}
}
两个功能:
func flagTapped(_ number: Int){
self.selcectedNumber = number
self.alreadyTapped = true
if number == correctAnswer{
scoreTitle = "Correct"
userScore += 1
self.isCorrect = true
self.isFadeOutOpacity = true
}else{
self.wrongAnswer = true
scoreTitle = "Wrong"
if userScore != 0{
userScore -= 1
}
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.showingScore = true
}
}
func askQuestion(){
countries = countries.shuffled()
correctAnswer = Int.random(in: 0...2)
self.isCorrect = false
self.isFadeOutOpacity = false
self.wrongAnswer = false
}
您必须声明一些新变量:)
希望我能帮上忙。
PS:Youtube上有一个100DaysOfSwiftUI的播放列表,其中包含几乎每个任务的解决方案。
https://www.youtube.com/watch?v=9AUGceRIUSA&list=PL3pUvT0fmHNhb3qcpvuym6KeM12eQK3T1