问题:
- 当用户按下“主页”按钮并返回应用程序时,如何暂停嵌套的UIView动画以激活alpha /不透明度?
- 我在下面的代码中遗漏了什么?谢谢。
醇>
背景
我有一个简单的嵌套UIView动画,可以在1分钟内从alpha = 0
到alpha = 1
的不同时间缓慢调整视图的alpha值。
当用户按下主页按钮时,UIView动画不会暂停,因此当应用程序恢复时,UIView动画会快进到动画的最后,在恢复应用程序时,alpha会立即从0更改为1。
因此,当用户按下设备主页按钮并暂时暂停应用程序时,我正在尝试暂停UIView动画。
我有一个暂停动画(pauseLayer
)的功能,然后重新开始动画(resumeLayer
)。从UIButton
调用它们时,这两个函数的效果很好。它会暂停alpha
并按预期恢复动画。 (但是,如果在动画暂停时按下主页按钮,则当它恢复时,alpha会立即从0更改为1。)
当我尝试在用户按下主页按钮(接收pauseLayer
通知)时调用WillResignActive
,然后返回应用程序(收到WillEnterForeground
通知)时,动画不会暂停和恢复,而是在恢复应用程序时,alpha会立即从0更改为1。
它似乎应该有效,但事实并非如此。
代码:
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var myView1: UIView!
@IBOutlet weak var myView2: UIView!
override func viewDidLoad() {
super.viewDidLoad()
setNotifications()
myAnimation()
}
@IBAction func myPauseButton(sender: UIButton) {
let layer = self.view.layer
pauseLayer(layer)
}
@IBAction func myResumeButton(sender: UIButton) {
let layer = self.view.layer
resumeLayer(layer)
}
func setNotifications() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ViewController.WillEnterForeground(_:)), name: UIApplicationWillEnterForegroundNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ViewController.WillResignActive(_:)), name: UIApplicationWillResignActiveNotification, object: nil)
}
func WillEnterForeground(notification : NSNotification) {
let layer = self.view.layer
resumeLayer(layer)
}
func WillResignActive(notification : NSNotification) {
let layer = self.view.layer
pauseLayer(layer)
}
func pauseLayer(layer: CALayer) {
let pausedTime: CFTimeInterval = layer.convertTime(CACurrentMediaTime(), fromLayer: nil)
layer.speed = 0.0
layer.timeOffset = pausedTime
}
func resumeLayer(layer: CALayer) {
let pausedTime: CFTimeInterval = layer.timeOffset
layer.speed = 1.0
layer.timeOffset = 0.0
layer.beginTime = 0.0
let timeSincePause: CFTimeInterval = layer.convertTime(CACurrentMediaTime(), fromLayer: nil) - pausedTime
layer.beginTime = timeSincePause
}
func myAnimation() {
self.myView1.alpha = 0
UIView.animateWithDuration(15, delay: 0, options: [.CurveEaseInOut], animations: {
self.myView1.alpha = 0.1
}, completion: {(finished: Bool) in
UIView.animateWithDuration(15, delay: 0, options: [.CurveEaseInOut], animations: {
self.myView1.alpha = 0.2
}, completion: {(finished: Bool) in
UIView.animateWithDuration(30, delay: 0, options: [.CurveEaseInOut], animations: {
self.myView1.alpha = 1
}, completion: nil)
})
})
self.myView2.alpha = 0
UIView.animateWithDuration(15, delay: 0, options: [.CurveEaseInOut], animations: {
self.myView2.alpha = 0.1
}, completion: {(finished: Bool) in
UIView.animateWithDuration(15, delay: 0, options: [.CurveEaseInOut], animations: {
self.myView2.alpha = 0.2
}, completion: {(finished: Bool) in
UIView.animateWithDuration(30, delay: 0, options: [.CurveEaseInOut], animations: {
self.myView2.alpha = 1
}, completion: nil)
})
})
}
}
修改
如果我将if (finished) {
添加到每个部分,然后按主页按钮,然后返回到应用程序,动画只会进入下一部分并停止,不再进一步。这样更好,但问题是resumeLayer
似乎不起作用,因此动画仍然停止并且不会继续。
self.myView2.alpha = 0
UIView.animateWithDuration(15, delay: 0, options: [.CurveEaseInOut, .LayoutSubviews, .AllowUserInteraction, .BeginFromCurrentState], animations: {
self.myView2.alpha = 0.1
}, completion: {(finished: Bool) in
if (finished) {
UIView.animateWithDuration(15, delay: 0, options: [.CurveEaseInOut, .LayoutSubviews, .AllowUserInteraction, .BeginFromCurrentState], animations: {
self.myView2.alpha = 0.2
}, completion: {(finished: Bool) in
if (finished) {
UIView.animateWithDuration(30, delay: 0, options: [.CurveEaseInOut, .LayoutSubviews, .AllowUserInteraction, .BeginFromCurrentState], animations: {
self.myView2.alpha = 1
}, completion: nil)
}
})
}
})
答案 0 :(得分:1)
您不需要使用UIView Animation来完成简单的淡入淡出。
您可以使用Timer对象和一个小数学来手动设置动画。
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = colorScheme.red
NotificationCenter.default.addObserver(self, selector: #selector(self.didBecomeActive), name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.didResignActive), name: NSNotification.Name.UIApplicationWillResignActive, object: nil)
}
func didBecomeActive() {
if case min_t..<max_t = t {
beginAnimation(at: t)
}
}
func didResignActive() {
_ = pauseAnimation()
}
var t = TimeInterval(0.0)
let min_t = TimeInterval(0)
let max_t = TimeInterval(100)
let delta = TimeInterval(0.1)
var timerObj: Timer?
func timer(_ aTimer: Timer) {
if t < max_t {
// Using a parabola
view.alpha = CGFloat(0.0001 * t * t)
} else {
_ = pauseAnimation()
}
t = t + 1
}
func beginAnimation(at t: TimeInterval = 0) {
self.t = t
timerObj = Timer.scheduledTimer(timeInterval: delta, target: self, selector: #selector(self.timer), userInfo: nil, repeats: true)
}
func pauseAnimation() -> TimeInterval {
timerObj?.invalidate()
return t
}
override func viewDidAppear(_ animated: Bool) {
beginAnimation()
}
}
但是,您的应用程序可能实际上更复杂,您的示例是简化。那么,这个怎么样?
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .red
NotificationCenter.default.addObserver(self, selector: #selector(self.WillEnterForeground(notification:)), name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.WillResignActive(notification:)), name: NSNotification.Name.UIApplicationWillResignActive, object: nil)
}
func WillEnterForeground(notification : NSNotification) {
if let timegap = endDate?.timeIntervalSince(startDate)
, timegap < duration {
beginAnimation(with: timegap/duration)
}
}
func WillResignActive(notification : NSNotification) {
let layer = self.view.layer
layer.removeAllAnimations()
}
var duration = TimeInterval(10)
var percentComplete = 0.0
var startDate: Date = Date()
var endDate: Date?
func beginAnimation(with percent: Double = 0.0) {
view.alpha = CGFloat(percent)
startDate = Date()
UIView.animateKeyframes(withDuration: duration * (1 - percent)
, delay: 0, options: UIViewKeyframeAnimationOptions.calculationModeLinear,
animations: {
if percent < 0.2 {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.2, animations: {
self.view.alpha = 0.1
})
}
if percent < 0.5 {
UIView.addKeyframe(withRelativeStartTime: 0.2, relativeDuration: 0.3, animations: {
self.view.alpha = 0.2
})
}
UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.7, animations: {
self.view.alpha = 1.0
})
}) { (b: Bool) in
if b == false {
self.endDate = Date()
if let timegap = self.endDate?.timeIntervalSince(self.startDate)
, timegap < self.duration {
self.view.alpha = CGFloat(timegap / self.duration)
}
}
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
beginAnimation()
}
}
主要思想是在动画开始之前获取时间以及结束时间。完成将告诉我们动画是否成功,但如果用户按下主页按钮,完成块将告诉我们错误。如果它是假的,我们可以捕获日期并找出时差并计算完成百分比。然后我们可以用这个百分比来确定剩下的时间。
希望有所帮助