如何防止用户离开并返回应用程序时完成动画

时间:2016-01-16 00:33:19

标签: ios swift animation swift2 nsnotificationcenter

我正在创建一个应用程序,我有一个button从屏幕的一侧移动到另一侧。我创建了一个暂停button,在选择button后暂停动画。这个button和函数工作正常。我还添加了一个函数,用于确定用户是否已退出应用程序。在这个函数中,我添加了暂停button函数。但是,当用户退出后返回应用程序时,它会显示暂停屏幕,但动画已完成。这是代码:

@IBAction func pauseButton(sender: UIButton) {
    let button = self.view.viewWithTag(1) as? UIButton!
    let layer = button!.layer
    pauseLayer(layer) // Pausing the animation
    view2.hidden = false // Showing pause screen
}
func pauseLayer(layer: CALayer) {
    let pausedTime: CFTimeInterval = layer.convertTime(CACurrentMediaTime(), fromLayer: nil)
    layer.speed = 0.0
    layer.timeOffset = pausedTime
}
@IBAction func startButton(sender: UIButton) {
    let button = UIButton()
    button.tag = 1 // so I can retrieve it in the pause function
    // Extra code to make the button look nice
    button.translatesAutoresizingMaskIntoConstraints = false // Allow constraints
    let topAnchorForButton = button.topAnchor.constraintEqualToAnchor(view.topAnchor, constant: 400)
    NSLayoutConstraint.activateConstraints([ // Adding constraints
        topAnchorForButton,
        button.leadingAnchor.constraintEqualToAnchor(view.topAnchor, constant: 120),
        button.widthAnchor.constraintEqualToConstant(65),
        button.heightAnchor.constraintEqualToConstant(65)
        ])
    self.view.layoutIfNeeded()
    [UIView.animateWithDuration(5.0, delay: 0.0, options: [.CurveLinear, .AllowUserInteraction], animations: {
        topAnchorForButton.constant = 0
        self.view.layoutIfNeeded()
        }, completion: nil )] // the animation

override func viewDidLoad() {
    super.viewDidLoad()
         NSNotificationCenter.defaultCenter().addObserver(self, selector: "pauseButton:", name: UIApplicationWillResignActiveNotification, object: nil) // When exists app
         NSNotificationCenter.defaultCenter().addObserver(self, selector: "pauseButton:", name: UIApplicationDidEnterBackgroundNotification, object: nil) // when goes to home screen
}

当我重新进入应用程序时,动画已完成。

这是我尝试过的代码,只播放和停止动画。我还在App Delegate中添加了一些东西,但它仍然不起作用:

的ViewController:

class Home: UIViewController {

func pauseAnimation(){
let button = self.view.viewWithTag(1) as? UIButton!
let layer = button!.layer
pauseLayer(layer) // Pausing the animation
}  
@IBAction func pauseButton(sender: UIButton) {
   pauseAnimation()
}
func pauseLayer(layer: CALayer) {
    let pausedTime: CFTimeInterval = layer.convertTime(CACurrentMediaTime(), fromLayer: nil)
    layer.speed = 0.0
    layer.timeOffset = pausedTime
}
@IBAction func startButton(sender: UIButton) {
    let button = UIButton()
    button.tag = 1 // so I can retrieve it in the pause function
    // Extra code to make the button look nice
    button.setTitle("Moving", forState: .Normal)
    button.setTitleColor(UIColor.redColor(), forState: .Normal)
    view.addSubview(button)
    button.translatesAutoresizingMaskIntoConstraints = false // Allow constraints
    let topAnchorForButton = button.topAnchor.constraintEqualToAnchor(view.topAnchor, constant: 400)
    NSLayoutConstraint.activateConstraints([ // Adding constraints
        topAnchorForButton,
        button.leadingAnchor.constraintEqualToAnchor(view.topAnchor, constant: 120),
        button.widthAnchor.constraintEqualToConstant(65),
        button.heightAnchor.constraintEqualToConstant(65)
        ])
    self.view.layoutIfNeeded()
    [UIView.animateWithDuration(10.0, delay: 0.0, options: [.CurveLinear, .AllowUserInteraction], animations: {
        topAnchorForButton.constant = 0
        self.view.layoutIfNeeded()
        }, completion: nil )] // the animation
}

App Delegate:

class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?
var vc = Home()
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
}
func applicationWillResignActive(application: UIApplication) {
   vc.pauseAnimation()
}

万一你想知道,这是恢复动画的代码:

@IBAction func resume(sender: UIButton) {
    let button = self.view.viewWithTag(100) as? UIButton!
    let layer = button!.layer 
    resumeLayer(layer)
}
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
}

退出应用时,它表示button或/和layer为零(致命错误...可选值为nil),因此崩溃。

请帮忙。在此先感谢...安东

3 个答案:

答案 0 :(得分:1)

尝试将此代码放入:

查看控制器:

pauseAnimation(){

    let button = self.view.viewWithTag(1) as? UIButton!
let layer = button!.layer
pauseLayer(layer) // Pausing the animation
view2.hidden = false // Showing pause screen

}

的AppDelegate:

func applicationWillResignActive(application: UIApplication) {

    vc.pauseAnimation()

}

为了能够从appDelegate中的视图控制器访问功能,请转到此处:link

答案 1 :(得分:1)

看看here。清单5-4显示了如何暂停和恢复动画的示例。您应该将代码移出AppDelegate,而视图控制器(Home)应该处理进出后台的问题。在首页的viewDidLoadviewWillAppear

NSNotificationCenter.defaultCenter().addObserver(
    self,
    selector: "resigningActive",
    name: UIApplicationWillResignActiveNotification,
    object: nil
)
NSNotificationCenter.defaultCenter().addObserver(
    self,
    selector: "becomeActive",
    name: UIApplicationDidBecomeActiveNotification,
    object: nil
)

你可能需要removeObserver,可能是在家里的deinit。然后你有:

func resigningActive() {
    pauseLayer(button!.layer)
}
func becomeActive() {
    resumeLayer(button!.layer)
}

此代码不需要另一个按钮来暂停/恢复,但如果需要,您也可以这样做。您可能需要在viewWillAppear中定义观察者,因为看起来您的代码将引用出口而不是viewDidLoad中尚未存在的出口。这意味着您必须编写代码才能在第一次调用viewWillAppear时挂钩观察者,或者您将为同一事件添加多个观察者。

你的pauseLayer也应该将pausedTime写入NSUserDefaults,而resumeLayer应该按照(未经测试)的方式将其读回:

// Write
NSUserDefaults.standarduserDefaults().setDouble(Double(pausedTime), forKey: "pausedTime")
// Read
pausedTime = CFTimeInterval(NSUserDefaults.standarduserDefaults().doubleForKey("pausedTime"))

答案 2 :(得分:1)

您需要了解动画如何在幕后工作。这在WWDC session 236 'Building Interruptible and Responsive Interactions'(你感兴趣的部分从17:45开始)中得到了很好的解释。在此期间,请阅读CABasicAnimation,并查看presentationLayer上的CALayer媒体资源(您需要下载到CALayer了解您想要达到的目标,也许您将需要使用CA(Basic)Animation来实现动画,尽管如果您已经很好地构建了代码,UIKit的动画方法可能仍然可以做到这一点。

基本上,视图或图层会立即获得您设置为动画一部分的结束值。然后动画从开始到结束开始。如果动画被中断,比如离开应用程序,在返回时,视图将使用它具有的值绘制(这是结束值,因为动画消失了)。

你想要的是当你离开应用程序时保存动画中的视图值,保存它,并在你的应用程序回到前台时从该点开始一个新动画到原始端点。您可以通过CALayer {{1} UIView {{1}请求框架或转换,获取您需要的任何内容,从而获得CALayer(不是presentationLayer)的当前位置} property。

构建自定义refreshControl以在任何`UIScrollView``中使用时,我遇到了这个问题。这段代码在Github上,你的相关代码在这里(它的Objective-C,但它不是很复杂,所以你应该能够跟随并重新实现你在Swift中所需的代码): JRTRefreshControlView.m,具体来说:

-(void)willMoveToWindow:(UIWindow *)newWindow当用户将应用程序移动到后台时,或者从superView中删除视图时,会调用此方法(newWindow将为nil)。

子类中动画的实际实现如下: JRTRotatingRefreshControlView.m,特别是

- (void) resumeRefreshingState方法是您想要查看的内容。

(还有saveRefreshingState,你可以在这里保存presentationLayer中的表示值,但是我的动画没有实现它。