[英]SwiftUI - Animate a view on button press
I have just finished lesson 6 of #hackingwithswift.我刚刚完成了#hackingwithswift 的第 6 课。 I'm going mad over a challenge that shouldn't be that hard at all...
我正在为一个根本不应该那么难的挑战而生气......
Here I have a working game called GuessTheFlag wherein the user must select the correct flag indicated then receives an alert before being passed to the next round.在这里,我有一个名为 GuessTheFlag 的工作游戏,其中用户必须选择指示的正确标志,然后在传递到下一轮之前收到警报。
My problem is simple: I would like to have the incorrect flag views become opaque and have the correct flag view rotate 360 degrees when an answer is chosen.我的问题很简单:我想让不正确的标志视图变得不透明,并且在选择答案时让正确的标志视图旋转 360 度。 This should all happen behind the alert until the user clicks 'continue'.
这应该全部发生在警报之后,直到用户单击“继续”。
Optional: I would also like to remove the alert altogether and have the game move on to the next round after the rotating animation has finished.可选:我还想完全删除警报,并在旋转动画完成后让游戏进入下一轮。 Can I bind the round change to the end of the animation?
我可以将圆形更改绑定到动画的结尾吗? Or do I have to use some sort of sleep() command?
还是我必须使用某种 sleep() 命令?
import SwiftUI
struct FlagView: View {
var flag: String
var body: some View {
Image(flag)
.renderingMode(.original)
.clipShape(Capsule())
.overlay(Capsule().stroke(Color.black, lineWidth: 2))
.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...2)
@State private var showingScore = false
@State private var scoreTitle = ""
@State private var score = 0
@State private var animate = false
var alert: Alert {
if scoreTitle == "Wrong" {
return Alert(title: Text(scoreTitle), message: Text("The correct answer was \(countries[correctAnswer])"), dismissButton: .default(Text("Restart")) {
self.askQuestion()
animate = false
})
}
else {
return Alert(title: Text(scoreTitle), message: Text("Your Score is \(score)"), dismissButton: .default(Text("Continue")) {
self.askQuestion()
animate = false
})
}
}
var body: some View {
ZStack{
LinearGradient(gradient: Gradient(colors: [.black,.blue, .orange]), startPoint: .top, endPoint: .bottom).edgesIgnoringSafeArea(.all)
VStack(spacing: 40) {
VStack{
Text("Tap the flag of")
.foregroundColor(.white)
Text(countries[correctAnswer])
.font(.largeTitle)
.fontWeight(.black)
.foregroundColor(.white)
}
ForEach(0 ..< 3){ number in
Button(action: {
withAnimation {
self.flagTapped(number)
animate.toggle()
}
}) {
FlagView(flag: self.countries[number])
}
}
Text("Your Score is \(score)")
.font(.headline)
.fontWeight(.black)
.foregroundColor(Color.white)
Spacer()
}
}
.alert(isPresented: $showingScore) {
alert
}
}
func flagTapped(_ number: Int) {
if number == correctAnswer {
scoreTitle = "Correct"
score += 1
} else {
scoreTitle = "Wrong"
score = 0
}
showingScore = true
}
func askQuestion() {
countries.shuffle()
correctAnswer = Int.random(in: 0...2)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Any help would be appreciated!任何帮助,将不胜感激! Thanks in advance
提前致谢
Just apply the view modifier opacity
and rotationEffect
on FlagView
and instead of using discrete values (such as .opacity(0.1)
) make it conditional:只需在
FlagView
上应用视图修饰符opacity
和rotationEffect
而不是使用离散值(例如.opacity(0.1)
)使其成为有条件的:
.opacity((self.animate && number != correctAnswer) ? 0.1 : 1.0)
The animation part will be automatically done be SwiftUI.动画部分将通过 SwiftUI 自动完成。 Please see my working example below:
请参阅下面的我的工作示例:
import SwiftUI
struct FlagView: View {
var flag: String
var body: some View {
Text(flag)
}
}
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 score = 0
@State private var animate = false
var alert: Alert {
if scoreTitle == "Wrong" {
return Alert(title: Text(scoreTitle), message: Text("The correct answer was \(countries[correctAnswer])"), dismissButton: .default(Text("Restart")) {
self.askQuestion()
})
}
else {
return Alert(title: Text(scoreTitle), message: Text("Your Score is \(score)"), dismissButton: .default(Text("Continue")) {
self.askQuestion()
})
}
}
var body: some View {
ZStack{
LinearGradient(gradient: Gradient(colors: [.black,.blue, .orange]), startPoint: .top, endPoint: .bottom).edgesIgnoringSafeArea(.all)
VStack(spacing: 40) {
VStack{
Text("Tap the flag of")
.foregroundColor(.white)
Text(countries[correctAnswer])
.font(.largeTitle)
.fontWeight(.black)
.foregroundColor(.white)
}
ForEach(0 ..< 3){ number in
Button(action: {
withAnimation(.easeInOut(duration: 0.5)) {
self.animate = true
}
self.flagTapped(number)
}) {
FlagView(flag: self.countries[number])
.opacity((self.animate && number != correctAnswer) ? 0.1 : 1.0)
.rotationEffect(.init(degrees: (self.animate && number == correctAnswer) ? 360.0 : 0.0))
}
}
Text("Your Score is \(score)")
.font(.headline)
.fontWeight(.black)
.foregroundColor(Color.white)
Spacer()
}
}
.alert(isPresented: $showingScore) {
alert
}
}
func flagTapped(_ number: Int) {
if number == correctAnswer {
scoreTitle = "Correct"
score += 1
} else {
scoreTitle = "Wrong"
score = 0
}
showingScore = true
}
func askQuestion() {
self.animate = false
countries.shuffle()
correctAnswer = Int.random(in: 0...2)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
For your optional question you could introduce a custom modifier (eg as described here ).为了您的选购问题(如例如,你可以引入一个自定义的修改在这里)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.