Как приостановить и возобновить анимацию - круглая панель KDCircularProgress

Я изменил код, взятый из https://github.com/kaandedeoglu/KDCircularProgress.

У меня есть небольшой UIView, который представляет собой таймер хода круга. Я сослался на него, а также создал экземпляр класса KDCircularProgress.

Мне удалось реализовать методы для запуска и сброса круговой шкалы выполнения таймера.

Но у меня возникают проблемы с перезапуском круглого индикатора выполнения, когда я приостанавливаю анимацию.

Преамбула моего кода:

import UIKit

class SomeTableViewController: UITableViewController {

//Circular progress vars
var currentCount = 1.0
let maxCount = 60.0

//Reference selected UIView & instantiate
@IBOutlet weak var circularProgressView: KDCircularProgress!

Запуск анимации - 60 секундная анимация:

 if currentCount != maxCount {
    currentCount += 1
    circularProgressView.animateToAngle(360, duration: 60, completion: nil)
    }

Чтобы остановить и сбросить анимацию:

currentCount = 0
circularProgressView.animateFromAngle(circularProgressView.angle, toAngle: 0, duration: 0.5, completion: nil)

Чтобы приостановить анимацию:

circularProgressView.pauseAnimation()

Как мне настроить метод перезапуска анимации после приостановки?

Большое спасибо за любые разъяснения. Это моя первая анимация, я сам пытался решить эту проблему, но не могу найти синтаксиса, применимого к моему конкретному случаю.

ОБНОВЛЕННОЕ РЕШЕНИЕ:

Спасибо @Duncan C за то, что направил меня на правильный путь.

Я решил свою проблему следующим образом ...

Поскольку я инициировал прогресс счетчика с помощью currentCount += 1, я подумал, что попытаюсь приостановить счетчик с помощью:

if currentCount != maxCount {
currentCount -= 1
circularProgressView.animateToAngle(360, duration: 60, completion: nil)
}

который, как я думал, будет иметь «чистый» эффект на счетчике (вычеркивая counter +=1 и counter -=1), чтобы эффективно остановить счетчик. Теоретически это должно означать, что счетчик обнулится, но он продолжает обратный отсчет.

Поэтому я вернулся к circularProgressView.pauseAnimation(), чтобы приостановить анимацию кругового счетчика.

Чтобы перезапустить анимацию после приостановки, мне пришлось изменить продолжительность, чтобы она отображала обновленную длительность, то есть время, в которое анимация была приостановлена.

Я применил здесь небольшой трюк и включил NSTimer, который все равно был в моем коде.

Чтобы перезапустить анимацию во время паузы:

    if currentCount != maxCount {
        currentCount += 1

        circularProgressView.animateToAngle(360, duration: NSTimeInterval(swiftCounter), completion: nil)
    }

Я не мог понять, как обновить продолжительность анимированной круглой полосы, но знал, как обновить прошедшее время с помощью таймера NSTimer с той же продолжительностью и скоростью обратного отсчета. Поэтому я пометил ссылку на обновленное значение таймера. Проблема решена ;)

Мой код:

import UIKit

class SomeFunkyTableViewController: UITableViewController {

//Circular progress variables
var currentCount = 0.0
let maxCount = 60.0

@IBOutlet weak var circularProgressView: KDCircularProgress!


//Timer countdown vars
var swiftTimer = NSTimer()
var swiftCounter = 60



@IBOutlet weak var startButton: UIButton!
@IBOutlet weak var timerView: UIView!

@IBOutlet weak var timerLabel: UILabel!

@IBOutlet weak var startView: UIView!

override func viewDidLoad() {

    circularProgressView.angle = 0

    timerLabel.text = String(swiftCounter)


        super.viewDidLoad()


override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


@IBAction func startButton(sender: AnyObject) {


    pauseBtn.alpha = 1.0

    playBtn.alpha = 1.0

    stopBtn.alpha = 1.0

    circularProgressView.hidden = false


    if currentCount != maxCount {
        currentCount += 1

        circularProgressView.animateToAngle(360, duration: 60, completion: nil)
    }

    startView.hidden = true
    timerView.hidden = false


    swiftTimer = NSTimer.scheduledTimerWithTimeInterval(1, target:self, selector: #selector(SomeFunkyTableViewController.updateCounter), userInfo: nil, repeats: true)



}


@IBOutlet weak var pauseBtn: UIButton!
@IBAction func pauseButton(sender: AnyObject) {

  circularProgressView.pauseAnimation()



    swiftTimer.invalidate()

    pauseBtn.alpha = 0.5

    playBtn.alpha = 1.0

    stopBtn.alpha = 1.0
}


@IBOutlet weak var playBtn: UIButton!
@IBAction func playButton(sender: AnyObject) {




    if currentCount != maxCount {
        currentCount += 1

        circularProgressView.animateToAngle(360, duration: NSTimeInterval(swiftCounter), completion: nil)
    }




    if !swiftTimer.valid {
        swiftTimer = NSTimer.scheduledTimerWithTimeInterval(1, target:self, selector: #selector(SomeFunkyTableViewController.updateCounter), userInfo: nil, repeats: true)
    }


    if swiftCounter == 0 {
        swiftTimer.invalidate()
    }


    pauseBtn.alpha = 1.0

    playBtn.alpha = 0.5

    stopBtn.alpha = 1.0

}


@IBOutlet weak var stopBtn: UIButton!
@IBAction func stopButton(sender: AnyObject) {

    currentCount = 0
    circularProgressView.animateFromAngle(circularProgressView.angle, toAngle: 0, duration: 0.5, completion: nil)

    circularProgressView.hidden = true

    timerView.hidden = true
    startView.hidden = false



    swiftTimer.invalidate()
    swiftCounter = 60
    timerLabel.text = String(swiftCounter)


    pauseBtn.alpha = 1.0

    playBtn.alpha = 1.0

    stopBtn.alpha = 0.5
}

func updateCounter() {

    swiftCounter -= 1
    timerLabel.text = String(swiftCounter)

    if swiftCounter == 0 {
        swiftTimer.invalidate()
    }
}


}

Боковое примечание: у меня есть два перекрывающихся представления - StartView и TimerView. Один скрывается при загрузке просмотра, поэтому ссылки скрыть / показать. И я затемняю кнопки по нажатию - воспроизведение / пауза / остановка.


person Katherine Jenkins    schedule 29.04.2016    source источник
comment
после паузы анимации .. что circularProgressView.angle регистрирует?   -  person Shubhank    schedule 29.04.2016
comment
@ katherine-jenkins, автор библиотеки здесь. Не забудьте открыть проблему Github в будущем, так мы сможем вместе улучшить библиотеку, если это будет необходимо. Если я правильно понимаю проблему, не забудьте попробовать установить для параметра relativeDuration значение false в методах анимации. Это должно помочь избавиться от таймеров и увеличения / уменьшения.   -  person Kaan Dedeoglu    schedule 23.06.2016


Ответы (2)


Для приостановки и возобновления анимации требуется специальный код. Возможно, у вас не получится сделать это, не изменив библиотеку, которую вы используете.

Хитрость заключается в том, чтобы установить скорость анимации на родительском слое, на котором размещена анимация, на 0 и записать смещение по времени анимации.

Вот несколько методов (написанных на Objective-C) из одного из моих проектов, которые приостанавливают и возобновляют анимацию:

- (void) pauseLayer: (CALayer *) theLayer
{
  CFTimeInterval mediaTime = CACurrentMediaTime();
  CFTimeInterval pausedTime = [theLayer convertTime: mediaTime fromLayer: nil];
  theLayer.speed = 0.0;
  theLayer.timeOffset = pausedTime;
}

//-----------------------------------------------------------------------------

- (void) removePauseForLayer: (CALayer *) theLayer;
{
  theLayer.speed = 1.0;
  theLayer.timeOffset = 0.0;
  theLayer.beginTime = 0.0;
}

//-----------------------------------------------------------------------------

- (void) resumeLayer: (CALayer *) theLayer;
{
  CFTimeInterval pausedTime = [theLayer timeOffset];
  [self removePauseForLayer: theLayer];
  CFTimeInterval mediaTime = CACurrentMediaTime();
  CFTimeInterval timeSincePause = 
    [theLayer convertTime: mediaTime fromLayer: nil] - pausedTime;
  theLayer.beginTime = timeSincePause;
}
person Duncan C    schedule 29.04.2016
comment
Гениальное решение! Примет быструю версию. - person Katherine Jenkins; 29.04.2016
comment
Возможно, вы захотите отредактировать свой ответ, чтобы показать версию кода Swift после того, как он заработает, поэтому он предоставляет версию решения Swifty. Кроме того, мы будем благодарны за голоса, если вам понравится этот ответ. - person Duncan C; 29.04.2016

Обратите внимание, что начиная с iOS 10 есть новый, лучший способ приостановить и возобновить UIView анимацию: UIViewPropertyAnimator.

У меня есть образец проекта (написанный на Swift) на Github, демонстрирующий этот новый класс UIViewPropertyAnimator. Вот ссылка: UIViewPropertyAnimator-test

Ниже приводится выдержка из README этого проекта:

UIViewPropertyAnimator позволяет легко создавать анимацию на основе UIView, которую можно приостанавливать, обращать вспять и прокручивать вперед и назад.

Объект UIViewPropertyAnimator принимает блок анимации, что очень похоже на старое семейство animate(withDuration:animations:) методов класса UIView. Однако UIViewPropertyAnimator можно использовать для запуска нескольких блоков анимации.

Имеется встроенная поддержка очистки анимации путем установки свойства fractionComplete в аниматоре. Однако НЕ существует автоматического механизма для наблюдения за ходом анимации.

Вы можете отменить UIViewPropertyAnimator анимацию, установив ее свойство isReversed, но есть некоторые особенности. Если вы измените свойство isReversed запущенного аниматора с false на true, анимация изменится на противоположную, но вы не можете установить свойство isReversed с true на false во время анимации и заставить его переключать направление с обратного на прямое «вживую». Вы должны сначала приостановить анимацию, переключить флаг isReversed, а затем перезапустить анимацию. (Используя аналогию с автомобилем, вы можете переключаться с прямого на задний ход во время движения, но вам нужно полностью остановиться, прежде чем вы сможете переключиться с заднего хода на движение.)

person Duncan C    schedule 21.06.2017