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

标签 ios swift animation swift2 nsnotificationcenter

我正在制作一个应用程序,其中有一个 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 中添加了一些东西,但它仍然不起作用:

View Controller :

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
}

应用委托(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( fatal error ...可选值为 nil),因此它崩溃了。

请帮忙。提前致谢...安东

最佳答案

您需要稍微了解一下动画的工作原理。这在 WWDC session 236 'Building Interruptible and Responsive Interactions' 中有很好的解释。 (您感兴趣的部分从 17:45 开始)。同时,阅读有关 CABasicAnimation 的内容,并检查 CALayer 上的 presentationLayer 属性(您需要下拉到 CALayer 为你想要实现的目标,也许你需要使用 CA(Basic)Animation 来实现动画,尽管 UIKit 的动画方法可能仍然可以做到这一点,如果你有结构良好的代码)。

基本上, View 或层将立即获得您设置为动画一部分的最终值。然后动画开始,从头到尾。如果动画被打断,比如离开应用程序,返回时将使用它具有的值绘制 View (当动画消失时,这些值是最终值)。

你想要的是当你离开应用程序时在动画中的那个点捕获 View 的值,保存它,并在你的应用程序返回前台时从那个点到原始端点开始一个新的动画.您可以通过从 CALayer 请求框架或变换来获取 CALayer(不是 UIView)的当前位置,无论您需要什么的 presentationLayer 属性。

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

-(void)willMoveToWindow:(UIWindow *)newWindow 当用户将应用程序移至后台时,或者当 View 从 superView 中移除时(newWindow 将为 nil),这将被调用。

而子类中动画的实际实现在这里: JRTRotatingRefreshControlView.m , 特别是

- (void) resumeRefreshingState 方法就是你要看的。

(还有 saveRefreshingState,您可以在其中保存来自 presentationLayer 的表示值,但我的动画没有实现它)。

关于ios - 当用户离开并返回应用程序时如何防止动画完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34822161/

相关文章:

ios - 在空的 UITextView 中启用返回键

iphone - NSTimer 和 NSDate 倒计时时钟在模拟器中工作,但在设备上不工作

iphone - 后台 MOC 的 "save:"无效(但返回 YES)

ios - 如何隐藏 View 的 subview ( float 操作按钮)以防止点击两个不同的区域

xcode - 为什么 viewDidLoad 在 didSelectItemAtIndexPath 之前运行?

python - 如何为 seaborn 的热图或相关矩阵制作动画?

ios - 使用 NSURLSession 和 Queue 上传数据

ios - DJI SDK 用户界面 : Customizing contentViewController in DULDefaultViewController

jQuery水平滚动显示

c++ - 使用 QPainter 流畅绘图