如何恢复核心动画时,应用程序回到前台
问题描述:
我有一个imageView,并希望它始终旋转360°,但我发现的问题是,当应用程序进入background
,然后回到,旋转动画将停止。 而我不想在应用程序回到前台时重新调用函数rotate360Degree()
,原因是我希望旋转动画将在进入背景时离开的位置开始,而不是从0再次旋转。 但是,当我呼叫功能resumeRotate()
,它不起作用。如何恢复核心动画时,应用程序回到前台
扩展如下:
extension UIImageView {
// 360度旋转图片
func rotate360Degree() {
let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation.z") // 让其在z轴旋转
rotationAnimation.toValue = NSNumber(value: .pi * 2.0) // 旋转角度
rotationAnimation.duration = 20 // 旋转周期
rotationAnimation.isCumulative = true // 旋转累加角度
rotationAnimation.repeatCount = MAXFLOAT // 旋转次数
rotationAnimation.autoreverses = false
layer.add(rotationAnimation, forKey: "rotationAnimation")
}
// 暂停旋转
func pauseRotate() {
layer.pauseAnimation()
}
// 恢复旋转
func resumeRotate() {
layer.resumeAnimation()
}
}
这里是层扩展:
var pauseTime:CFTimeInterval!
extension CALayer {
//暂停动画
func pauseAnimation() {
pauseTime = convertTime(CACurrentMediaTime(), from: nil)
speed = 0.0
timeOffset = pauseTime
}
//恢复动画
func resumeAnimation() {
// 1.取出时间
pauseTime = timeOffset
// 2.设置动画的属性
speed = 1.0
timeOffset = 0.0
beginTime = 0.0
// 3.设置开始动画
let startTime = convertTime(CACurrentMediaTime(), from: nil) - pauseTime
beginTime = startTime
}
}
我可以解决上述“停止”的问题与CADisplayLink,但动画将不会从旋转它离开的位置(始终旋转)。 我想知道如何用CADisplayLink解决它? 以上核心动画如何?
displayLink = CADisplayLink(target: self, selector: #selector(rotateImage))
displayLink.add(to: .current, forMode: .commonModes)
func rotateImage(){
let angle = CGFloat(displayLink.duration * Double.pi/18)
artworkImageView.transform = artworkImageView.transform.rotated(by: angle)
}
答
可以与基于UIKit
的更高级别的块动画API做到这一点。如果您想要持续20.0秒的持续旋转视图。你可以像一个函数:
func animateImageView()
{
UIView.animate(withDuration: 10.0, delay: 0.0, options: [.beginFromCurrentState, .repeat, .curveLinear], animations:
{ [unowned self] in
var transform = self.imageView.transform
transform = transform.concatenating(CGAffineTransform(rotationAngle: CGFloat.pi))
self.imageView.transform = transform
},
completion:
{ _ in
UIView.animate(withDuration: 10.0, delay: 0.0, options: [.beginFromCurrentState, .curveLinear], animations:
{ [unowned self] in
var transform = self.imageView.transform
transform = transform.concatenating(CGAffineTransform(rotationAngle: CGFloat.pi/2.0))
self.imageView.transform = transform
})
})
}
这将只是一旦完成旋转它的另一个180的360度旋转而旋转,然后通过180度视图。 .repeat
选项将导致它无限期地重复。但是,当应用程序背景时,动画将停止。为此,我们需要保存被旋转视图的表示层的状态。我们可以通过存储表示层的CGAffineTransform
,然后在应用程序回到前景时将该转换设置为正在动画的视图。下面是一个例子与UIImageView
class ViewController: UIViewController
{
@IBOutlet weak var imageView: UIImageView!
var imageViewTransform = CGAffineTransform.identity
override func viewDidLoad()
{
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(self.didEnterBackground), name: .UIApplicationDidEnterBackground, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.willEnterForeground), name: .UIApplicationWillEnterForeground, object: nil)
}
override func viewDidAppear(_ animated: Bool)
{
super.viewDidAppear(animated)
animateImageView()
}
deinit
{
NotificationCenter.default.removeObserver(self)
}
func didEnterBackground()
{
imageViewTransform = imageView.layer.presentation()?.affineTransform() ?? .identity
}
func willEnterForeground()
{
imageView.transform = imageViewTransform
animateImageView()
}
func animateImageView()
{
UIView.animate(withDuration: 10.0, delay: 0.0, options: [.beginFromCurrentState, .repeat, .curveLinear], animations:
{ [unowned self] in
var transform = self.imageView.transform
transform = transform.concatenating(CGAffineTransform(rotationAngle: CGFloat.pi))
self.imageView.transform = transform
},
completion:
{ _ in
UIView.animate(withDuration: 10.0, delay: 0.0, options: [.beginFromCurrentState, .curveLinear], animations:
{ [unowned self] in
var transform = self.imageView.transform
transform = transform.concatenating(CGAffineTransform(rotationAngle: CGFloat.pi/2.0))
self.imageView.transform = transform
})
})
}
}
导致此:
@Hi beyowulf。感谢您的详细回复。我会尝试解决您的问题。但问题是持续时间不适用于后台或前台应用程序。它只涉及用户的行为。例如,该应用程序是音乐播放器,imageView用于音乐作品,用户可以用后台模式听音乐30分钟,2小时或更长时间。 – Ringo
我不明白你的意见。应用程序在后台的持续时间可以是任何无关紧要,只要应用程序停留在内存中即可。我认为问题是如何为视图设置动画,以便在应用程序背景时恢复动画,继续播放,就好像它从未背景一样。情况并非如此吗? – beyowulf
哦,对不起,我误解了你的代码中的数字10。这是动画的持续时间,而不是应用程序在后台的时间。 – Ringo