【发布时间】:2021-12-21 16:12:28
【问题描述】:
我试图在我的应用程序中创建一个动画,当一个特定的动作发生时,它本质上会使给定元素的背景改变颜色并返回 x 次以创建一种“脉冲”效果。应用程序本身非常大,但我设法在一个非常基本的应用程序中重新创建了这个问题。
所以ContentView如下:
struct ContentView: View {
struct Constants {
static let animationDuration = 1.0
static let backgroundAlpha: CGFloat = 0.6
}
@State var isAnimating = false
@ObservedObject var viewModel = ContentViewViewModel()
private let animation = Animation.easeInOut(duration: Constants.animationDuration).repeatCount(6, autoreverses: false)
var body: some View {
VStack {
Text("Hello, world!")
.padding()
Button(action: {
animate()
}) {
Text("Button")
.foregroundColor(Color.white)
}
}
.background(isAnimating ? Color.red : Color.blue)
.onReceive(viewModel.$shouldAnimate, perform: { _ in
if viewModel.shouldAnimate {
withAnimation(self.animation, {
self.isAnimating.toggle()
})
}
})
}
func animate() {
self.viewModel.isNew = true
}
}
然后我的 viewModel 是:
import Combine
import SwiftUI
class ContentViewViewModel: ObservableObject {
@Published var shouldAnimate = false
@Published var isNew = false
var cancellables = Set<AnyCancellable>()
init() {
$isNew
.sink { result in
if result {
self.shouldAnimate = true
}
}
.store(in: &cancellables)
}
}
所以我遵循的逻辑是,当点击按钮时,我们将“isNew”设置为 true。这又是一个发布者,当设置为 true 时,将“shouldAnimate”设置为 true。在 ContentView 中,当接收到 shouldAnimate 并且为 true 时,我们切换 VStack 的背景颜色 x 次。
我使用这个 'shouldAnimate' 发布属性的原因是因为在实际应用程序中,可能需要几个不同的动作来触发动画,因此将它绑定到一个我们可以监听的变量感觉更简单在 ContentView 中。
所以在上面的代码中,我们应该切换 isAnimating bool 6 次。所以,我们从 false 开始,然后切换如下:
1:真,2:假,3:真,4:假,5:真,6:假
所以我希望最终结果为 false,因此背景为白色。但是,这就是我得到的:
我尝试更改 repeatCount(以防我误解了计数的工作原理):
private let animation = Animation.easeInOut(duration: Constants.animationDuration).repeatCount(7, autoreverses: false)
我得到以下信息:
无论计数如何,我总是以 true 结束。
更新:
我现在已经设法通过使用以下循环获得我正在寻找的效果:
for i in 0...5 {
DispatchQueue.main.asyncAfter(deadline: .now() + Double(i), execute: {
withAnimation(self.animation, {
self.isAnimating.toggle()
})
})
}
不确定这是不是最好的方法....
【问题讨论】:
-
我认为您误解了
Animations的工作原理。当您将变量包装在withAnimation()中时,您实际上是在订阅动画以观察变量的变化。当发生这种变化时,动画就会运行。动画不会更改变量。它最终为真的原因是因为你只将它从假设置为真。你的self.isAnimating.toggle()只运行一次。 -
谢谢你 - 是的,我显然在这里以错误的方式查看动画......
-
SwiftUI Lab 有很多关于动画的博文。
-
我看了你的动画,我不确定我能分辨出它们之间的区别。第一个和第二个示例中您不喜欢第三个示例中的哪些内容?
标签: animation swiftui toggle combine