Gal*_*her 3 animation rotation continuous swift
我想将按钮用作切换按钮-单击一次即可无限旋转图片。再次单击,图像停止,再次单击,重新启动。
我发现此答案有助于使动画继续进行: 在Swift中将视图无限地旋转360度?
但是,我不清楚如何停止事情。我已经实现了下面的代码,而且似乎可以正常工作,但是很好奇这是否是停止动画的正确方法,或者是否还有其他首选方法。另外-我的旋转持续进行到完成为止,但是我想知道是否可以在按下按钮时冻结该位置的旋转(我在下面的第二次尝试中尝试了.removeAllAnimations(),但似乎在所有。
@IBOutlet weak var imageView: UIImageView!
var stopRotation = true
func rotateView(targetView: UIView, duration: Double = 1.0) {
if !stopRotation {
UIView.animate(withDuration: duration, delay: 0.0, options: .curveLinear, animations: {
targetView.transform = targetView.transform.rotated(by: CGFloat(Double.pi))
}) { finished in
self.rotateView(targetView: targetView, duration: duration)
}
}
}
@IBAction func spinPressed(_ sender: UIButton) {
stopRotation = !stopRotation
if !stopRotation {
rotateView(targetView: imageView)
}
}
Run Code Online (Sandbox Code Playgroud)
这确实有效。我还想知道是否有可能停止动画的自旋。设置方式是,动画在停止之前会完整旋转180度。我也尝试过在spinPressed动作中添加removeAnimation,并摆脱了rotateView内部的stopRotation检查,但这似乎不起作用–旋转会继续,并且如果再次按下spinPressed只会变得更快(请参见下文):
@IBOutlet weak var imageView: UIImageView!
var stopRotation = true
func rotateView(targetView: UIView, duration: Double = 1.0) {
UIView.animate(withDuration: duration, delay: 0.0, options: .curveLinear, animations: {
targetView.transform = targetView.transform.rotated(by: CGFloat(Double.pi))
}) { finished in
self.rotateView(targetView: targetView, duration: duration)
}
}
@IBAction func spinPressed(_ sender: UIButton) {
stopRotation = !stopRotation
if stopRotation {
imageView.layer.removeAllAnimations()
} else {
rotateView(targetView: imageView)
}
}
Run Code Online (Sandbox Code Playgroud)
欢迎确认第一种方法是否正确。而且,如果有一种方法可以阻止旋转在中间旋转,那也将受到欢迎(以及使我直接意识到我对removeAllAnimations的错误思考)。
谢谢!JG
有两种方法可以解决您的问题:
如果支持iOS 10+,则可以使用UIViewPropertyAnimator,您可以暂停和重新启动其动画(从暂停的位置恢复):
private var animator: UIViewPropertyAnimator?
@IBAction func didTapButton(_ sender: Any) {
guard let animator = animator else {
createAnimation()
return
}
if animator.isRunning {
animator.pauseAnimation()
} else {
animator.startAnimation()
}
}
/// Create and start 360 degree animation
///
/// This will fire off another animation when one 360° rotation finishes.
private func createAnimation() {
animator = UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 4, delay: 0, options: .curveLinear, animations: {
UIView.animateKeyframes(withDuration: 4, delay: 0, animations: {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 1.0 / 3.0) {
self.animatedView.transform = .init(rotationAngle: .pi * 2 * 1 / 3)
}
UIView.addKeyframe(withRelativeStartTime: 1.0 / 3.0, relativeDuration: 1.0 / 3.0) {
self.animatedView.transform = .init(rotationAngle: .pi * 2 * 2 / 3)
}
UIView.addKeyframe(withRelativeStartTime: 2.0 / 3.0, relativeDuration: 1.0 / 3.0) {
self.animatedView.transform = .identity
}
})
}, completion: { [weak self] _ in
self?.createAnimation()
})
}
Run Code Online (Sandbox Code Playgroud)您也可以使用UIKit Dynamics旋转项目。然后UIDynamicItemBehavior,您可以删除正在执行旋转的,它只会停在原处。它会自动将视图transform保留在原位置。然后,要恢复旋转,只需UIDynamicItemBehavior再次为旋转添加一个:
private lazy var animator: UIDynamicAnimator = UIDynamicAnimator(referenceView: view)
private var rotate: UIDynamicItemBehavior?
@IBAction func didTapButton(_ sender: Any) {
if let rotate = rotate {
animator.removeBehavior(rotate)
self.rotate = nil
} else {
rotate = UIDynamicItemBehavior(items: [animatedView])
rotate?.allowsRotation = true
rotate?.angularResistance = 0
rotate?.addAngularVelocity(1, for: animatedView)
animator.addBehavior(rotate!)
}
}
Run Code Online (Sandbox Code Playgroud)
这不能让您轻松地控制时间的旋转速度,而是由决定的angularVelocity,但这是一个很好的简单方法(并支持iOS 7.0及更高版本)。
停止动画并将其留在停止位置的传统方法是捕获presentationLayer动画的(显示动画在飞行中的位置)。然后,您可以获取当前状态,停止动画,并将转换设置为所presentationLayer报告的内容。
private var isAnimating = false
@IBAction func didTapButton(_ sender: Any) {
if isAnimating {
let transform = animatedView.layer.presentation()!.transform
animatedView.layer.removeAllAnimations()
animatedView.layer.transform = transform
} else {
let rotate = CABasicAnimation(keyPath: "transform.rotation")
rotate.byValue = 2 * CGFloat.pi
rotate.duration = 4
rotate.repeatCount = .greatestFiniteMagnitude
animatedView.layer.add(rotate, forKey: nil)
}
isAnimating = !isAnimating
}
Run Code Online (Sandbox Code Playgroud)如果要使用UIView基于块的动画,则必须捕获停止动画的角度,这样才能知道从哪里重新开始动画。诀窍是抓住m12和m11的CATransform3D:
angle = atan2(transform.m12, transform.m11)
Run Code Online (Sandbox Code Playgroud)
因此,将产生:
private var angle: CGFloat = 0
private var isAnimating = false
@IBAction func didTapButton(_ sender: Any) {
if isAnimating {
let transform = animatedView.layer.presentation()!.transform
angle = atan2(transform.m12, transform.m11)
animatedView.layer.removeAllAnimations()
animatedView.layer.transform = transform
} else {
UIView.animate(withDuration: 4, delay: 0, options: .curveLinear, animations: {
UIView.animateKeyframes(withDuration: 4, delay: 0, options: .repeat, animations: {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 1.0 / 3.0) {
self.animatedView.transform = .init(rotationAngle: self.angle + .pi * 2 * 1 / 3)
}
UIView.addKeyframe(withRelativeStartTime: 1.0 / 3.0, relativeDuration: 1.0 / 3.0) {
self.animatedView.transform = .init(rotationAngle: self.angle + .pi * 2 * 2 / 3)
}
UIView.addKeyframe(withRelativeStartTime: 2.0 / 3.0, relativeDuration: 1.0 / 3.0) {
self.animatedView.transform = .init(rotationAngle: self.angle)
}
})
})
}
isAnimating = !isAnimating
}
Run Code Online (Sandbox Code Playgroud)您可以自己旋转对象CADisplayLink,该操作会将角度更新为一些计算值。然后停止旋转就像使显示链接失效一样简单,从而将其保留在停止时的位置。然后,您只需将显示链接添加回您的运行循环即可恢复动画。
这种技术为您提供了很多控制权,但是却是最不完善的方法。
| 归档时间: |
|
| 查看次数: |
566 次 |
| 最近记录: |