2016-09-17 2 views
0

Вопрос:Приостановка и возобновление UIView анимации с альфа не работает, когда пользователь нажимает кнопку Домой

  1. Как приостановить вложенную UIView анимации, которая оживляет альфа/непрозрачность, когда пользователь нажимает на дом и возвращается в приложение?
  2. Что я пропустил в коде ниже? Спасибо.

фон:

У меня есть простая вложенная UIView анимация, которая регулирует альфа вид медленно в разное время от alpha = 0 до alpha = 1 за 1 минуту.

Когда пользователь нажимает кнопку «Домой», анимация UIView не приостанавливается, поэтому, когда приложение возобновляется, анимация UIView продвигается вперед до самого конца анимации, альфа мгновенно меняется с 0 на 1 при возобновлении приложения ,

Итак, я пытаюсь приостановить анимацию UIView, когда пользователь нажимает кнопку «Главная страница» и временно приостанавливает приложение.

У меня есть функция, которая приостанавливает анимацию (pauseLayer), а затем возобновляет анимацию (resumeLayer). Эти две функции отлично работают при вызове из UIButton. Он приостанавливает alpha и возобновляет анимацию, как ожидалось. (Тем не менее, при нажатии на кнопку Home, пока анимация приостановлена, когда он возобновляет альфа изменения мгновенно от 0 до 1.)

При попытке вызова pauseLayer, когда пользователь нажимает на кнопку Home (получение уведомления WillResignActive), а затем возвращается обратно в приложение (получая уведомление WillEnterForeground), анимация не приостанавливается и не возобновляется, вместо этого альфа мгновенно меняется с 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) 
       }) 
     }) 
    } 

} 

EDIT:

Если добавить if (finished) { к каждому разделу, а затем нажмите на кнопку Home, затем вернитесь в приложение, то анимация только переходит к следующему разделу и останавливается, не далее. Это лучше, но проблема в том, что 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

Может быть, вместо того, чтобы UIApplicationWillEnterForeground вы должны использовать UIApplicationDidBecomeActive – DerrickHo328

+0

К сожалению, это не сработало @ Calimari328, но спасибо, хотя я не пробовал это. – user4806509

ответ

1

Вам не нужно использовать анимацию UIView для достижения простого выцветания.

Вы можете использовать объект Timer и немного Math для его ручной анимации.

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() 
    } 

} 

Основная идея - получить время до начала анимации и время ее окончания. По завершении мы скажем правду, если анимация прошла успешно, но если пользователь нажмет кнопку «домой», блок завершения скажет нам ложь. Если это неверно, мы можем зафиксировать дату и узнать разницу во времени и рассчитать процент завершения. то мы можем использовать этот процент, чтобы определить оставшееся время.

Надежда, что помогает

+0

Это дает некоторые идеи. Благодарю. Я надеялся сохранить 'UIView.animateWithDuration', поскольку анимация ключевого кадра иногда может быть ограничена. Исходный метод работает, когда нажимается кнопка, но, к сожалению, помещает приложение в фоновый режим. Вы правы, есть более сложная анимация, чем здесь. Однако эта краткая версия бросает ту же самую проблему в отношении альфа-анимаций. Краткий пример здесь заключается в том, чтобы все было просто, чтобы следовать. Я не понимаю, почему анимация быстро продвигается вперед в фоновом режиме, когда каждая часть не завершилась? – user4806509

Смежные вопросы