SwiftUI rotationEffect() 内部动画奇怪的行为,我无法禁用它
SwiftUI rotationEffect() internal animation strange behavior and I can't disable it
我正在探索如何处理无限动画。我学习了如何启动它并尝试手动停止它。我找到的最佳解决方案是计算动画 属性 的当前值并在停止动画时设置它。好吧,除了一瞬间,它工作得很好。看起来 rotationEffect()
使用内置的自我动画来停止旋转。如果你尝试立即开始和停止动画,你会看到类似速度物理的东西。有点像.spring
动画,但我用了.linear
。我尝试使用 withAnimation(.none)
禁用它,但失败了。
如果您停止旋转接近 90 度(但小于 90 度),它会超过 90 度。
我看到解决此问题的唯一方法是使用 CG 框架构建我自己的旋转修改器。
还有其他想法吗?
代码如下:
import SwiftUI
class AnimationHandler: ObservableObject{
@Published var isStarted: Bool = true
}
struct AnimationStopping: View {
@ObservedObject var animationHandler = AnimationHandler()
var body: some View {
VStack{
Spacer()
AnimatedRectObservedObject(animationHandler: self.animationHandler)
Spacer()
Button(action: {
self.animationHandler.isStarted.toggle()
}){
Text(self.animationHandler.isStarted ? "stop animation" : "start animation")
}
}
}
}
struct AnimatedRectObservedObject: View{
@State var startTime: Date = Date()
@State var angle: Double = 0
@ObservedObject var animationHandler: AnimationHandler
var animation: Animation = Animation.linear(duration: 1).repeatForever(autoreverses: false)
var body: some View{
VStack{
Rectangle()
.fill(Color.green)
.frame(width: 200, height: 200)
.rotationEffect(Angle(degrees: angle))
.animation(animationHandler.isStarted ? animation : .default)
Spacer()
}.onReceive(animationHandler.objectWillChange){
let newValue = self.animationHandler.isStarted
if newValue == false{
let timePassed = Date().timeIntervalSince(self.startTime)
let fullSecondsPassed = Double(Int(timePassed))
let currentStage = timePassed - fullSecondsPassed
let newAngle = self.angle - 90 + currentStage * 90
withAnimation(.none){//not working:(((
self.angle = newAngle
}
}else {
self.startTime = Date()
self.angle += 90
}
}
.onAppear{
self.angle += 90
self.startTime = Date()
}
}
}
更新:
实际上,自定义修饰符无济于事。我使用它,在上面打印,通过 @ObservableObject
取回它的实际动画时间并观看了这个:
current animation position 0.15000057220458984
current animation position 0.15833377838134766
current animation position 0.16666698455810547
current animation position 0.17500019073486328
current animation position 0.1833333969116211
current animation position 0.1916666030883789
current animation position 0.19999980926513672
current animation position 0.20833301544189453
animated from 0.0 to 1.0 stopped at 0.20833301544189453
current animation position 0.21662975207982527
current animation position 0.22470279080698674
current animation position 0.2323109631133775
current animation position 0.23920465996798157
current animation position 0.24513085941998725
current animation position 0.24984809499710536
current animation position 0.25314617272852047
current animation position 0.25487106971286266
current animation position 0.25495114064688096
current animation position 0.25341608746384736
current animation position 0.25040891469689086
current animation position 0.24617629182102974
current animation position 0.2410420152482402
current animation position 0.23537338342976
current animation position 0.2295457124710083
current animation position 0.2239141315640154
current animation position 0.21879699627515947
current animation position 0.2144686846222612
current animation position 0.2111600160587841
current animation position 0.20906241873944964
current animation position 0.20833301544189453
答案很简单:
.animation(animationHandler.isStarted ? animation : .linear(duration: 0))
我正在探索如何处理无限动画。我学习了如何启动它并尝试手动停止它。我找到的最佳解决方案是计算动画 属性 的当前值并在停止动画时设置它。好吧,除了一瞬间,它工作得很好。看起来 rotationEffect()
使用内置的自我动画来停止旋转。如果你尝试立即开始和停止动画,你会看到类似速度物理的东西。有点像.spring
动画,但我用了.linear
。我尝试使用 withAnimation(.none)
禁用它,但失败了。
如果您停止旋转接近 90 度(但小于 90 度),它会超过 90 度。
我看到解决此问题的唯一方法是使用 CG 框架构建我自己的旋转修改器。
还有其他想法吗?
代码如下:
import SwiftUI
class AnimationHandler: ObservableObject{
@Published var isStarted: Bool = true
}
struct AnimationStopping: View {
@ObservedObject var animationHandler = AnimationHandler()
var body: some View {
VStack{
Spacer()
AnimatedRectObservedObject(animationHandler: self.animationHandler)
Spacer()
Button(action: {
self.animationHandler.isStarted.toggle()
}){
Text(self.animationHandler.isStarted ? "stop animation" : "start animation")
}
}
}
}
struct AnimatedRectObservedObject: View{
@State var startTime: Date = Date()
@State var angle: Double = 0
@ObservedObject var animationHandler: AnimationHandler
var animation: Animation = Animation.linear(duration: 1).repeatForever(autoreverses: false)
var body: some View{
VStack{
Rectangle()
.fill(Color.green)
.frame(width: 200, height: 200)
.rotationEffect(Angle(degrees: angle))
.animation(animationHandler.isStarted ? animation : .default)
Spacer()
}.onReceive(animationHandler.objectWillChange){
let newValue = self.animationHandler.isStarted
if newValue == false{
let timePassed = Date().timeIntervalSince(self.startTime)
let fullSecondsPassed = Double(Int(timePassed))
let currentStage = timePassed - fullSecondsPassed
let newAngle = self.angle - 90 + currentStage * 90
withAnimation(.none){//not working:(((
self.angle = newAngle
}
}else {
self.startTime = Date()
self.angle += 90
}
}
.onAppear{
self.angle += 90
self.startTime = Date()
}
}
}
更新:
实际上,自定义修饰符无济于事。我使用它,在上面打印,通过 @ObservableObject
取回它的实际动画时间并观看了这个:
current animation position 0.15000057220458984
current animation position 0.15833377838134766
current animation position 0.16666698455810547
current animation position 0.17500019073486328
current animation position 0.1833333969116211
current animation position 0.1916666030883789
current animation position 0.19999980926513672
current animation position 0.20833301544189453
animated from 0.0 to 1.0 stopped at 0.20833301544189453
current animation position 0.21662975207982527
current animation position 0.22470279080698674
current animation position 0.2323109631133775
current animation position 0.23920465996798157
current animation position 0.24513085941998725
current animation position 0.24984809499710536
current animation position 0.25314617272852047
current animation position 0.25487106971286266
current animation position 0.25495114064688096
current animation position 0.25341608746384736
current animation position 0.25040891469689086
current animation position 0.24617629182102974
current animation position 0.2410420152482402
current animation position 0.23537338342976
current animation position 0.2295457124710083
current animation position 0.2239141315640154
current animation position 0.21879699627515947
current animation position 0.2144686846222612
current animation position 0.2111600160587841
current animation position 0.20906241873944964
current animation position 0.20833301544189453
答案很简单:
.animation(animationHandler.isStarted ? animation : .linear(duration: 0))