CABasicAnimation отзывчивость

У меня есть пользовательский интерфейс UIActivityIndicatorView. Это представление с CAAnimation на его уровне. Проблема в следующем:

Я делаю тяжелую работу и создаю много просмотров. Это занимает примерно 0,5 секунды. Для плавности решил использовать индикатор активности, пока «бывает». С индикатором активности по умолчанию все было нормально, однако с тем, что я написал, я получаю неожиданные результаты.

Итак, когда представление загружается, я запускаю индикатор активности, который начинает анимацию. Когда начинается тяжелая работа, мой вид замирает на 0,5 секунды, а когда он закончен, я прекращаю анимировать его, и он исчезает. Такое «замирание» выглядит очень неприятно глазу. Потому что идея заключалась в том, чтобы продолжать анимацию, пока другие представления инициализируются и добавляются как подпредставления (хотя и скрытые).

Я подозреваю, что проблема в том, что мой «индикатор активности» не асинхронен или просто неправильно закодирован.

Вот его код:

class CustomActivityIndicatorView: UIView {

// MARK - Variables

var colors = [UIColor.greenColor(),UIColor.grayColor(),UIColor.blueColor(),UIColor.redColor()]

var colorIndex = 0

var animation: CABasicAnimation!

lazy var customView : UIView! = {
    let frame : CGRect = CGRectMake(0.0, 0.0, 100, 100)
    let view = UIView(frame: frame)
    image.frame = frame
    image.center = view.center
    view.backgroundColor = UIColor.greenColor()
    view.clipsToBounds = true
    view.layer.cornerRadius = frame.width/2
    return view
}()

var isAnimating : Bool = false
var hidesWhenStopped : Bool = true

var from: NSNumber = 1.0
var to: NSNumber = 0.0

var growing = false

override func animationDidStart(anim: CAAnimation!) {
}

override func animationDidStop(anim: CAAnimation!, finished flag: Bool) {
    growing = !growing

    if growing {
        colorIndex++
        if colorIndex == colors.count {
            colorIndex = 0
        }
        println(colorIndex)
        customView.backgroundColor = colors[colorIndex]
        from = 0.0
        to = 1.0
    } else {
        from = 1.0
        to = 0.0
    }

    if isAnimating {
        addPulsing()
        resume()
    }
}

// MARK - Init

required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)

    self.addSubview(customView)

    addPulsing()
    pause()
    self.hidden = true
}

// MARK - Func

func addPulsing() {
    let pulsing : CABasicAnimation = CABasicAnimation(keyPath: "transform.scale")

    pulsing.duration = 0.4
    pulsing.removedOnCompletion = false
    pulsing.fillMode = kCAFillModeForwards
    pulsing.fromValue = from
    pulsing.toValue = to
    pulsing.delegate = self

    let layer = customView.layer

    layer.addAnimation(pulsing, forKey: "pulsing")
}

func pause() {
    let layer = customView.layer

    let pausedTime = layer.convertTime(CACurrentMediaTime(), fromLayer: nil)

    layer.speed = 0.0
    layer.timeOffset = pausedTime

    isAnimating = false
}

func resume() {
    let layer = customView.layer

    let pausedTime : CFTimeInterval = layer.timeOffset

    layer.speed = 1.0
    layer.timeOffset = 0.0
    layer.beginTime = 0.0

    let timeSincePause = layer.convertTime(CACurrentMediaTime(), fromLayer: nil) - pausedTime
    layer.beginTime = timeSincePause

    isAnimating = true
}

func startAnimating () {

    if isAnimating {
        return
    }

    if hidesWhenStopped {
        self.hidden = false
    }
    resume()
}

func stopAnimating () {
    let layer = customView.layer

    if hidesWhenStopped {
        self.hidden = true
    }
    pause()
    layer.removeAllAnimations()
}

deinit {
    println("Spinner Deinitied")
}
}

Что касается метода animationDidStop:

Идея следующая. Вид пульсирует, а после уменьшения снова начинает расти, а цвет фона меняется.

Есть идеи, что я делаю не так?


person Olexiy Burov    schedule 14.08.2015    source источник
comment
Я обнаружил похожую проблему здесь stackoverflow.com/questions/1614921/. Однако это произошло в 2009 году, и я все еще пытаюсь выяснить, могу ли я выделять представления в основном потоке и запускать простую анимацию во втором потоке (что CA делает по определению) в 2015 году. Поскольку UIActivityIndicator отлично работает в этом сценарии . В чем может быть проблема с моим индикатором активности?   -  person Olexiy Burov    schedule 14.08.2015
comment
Я считаю, что нашел источник проблемы. Методы делегата didStop и didStart (где я перезапускаю свою анимацию) работают в основном потоке, поэтому они заблокированы, и следующий цикл анимации зависает до тех пор, пока не будут выполнены вычисления в основном потоке. Я попробую использовать CAKeyFrameAnimation для своей идеи и вскоре опубликую здесь результаты.   -  person Olexiy Burov    schedule 14.08.2015


Ответы (1)


Решил с помощью CAKeyFrameAnimation для достижения того же эффекта. Для всех, кто сталкивается с одной и той же проблемой, помните, что animationDidStart и animationDidStop запускаются в основном потоке, поэтому все, что вы делаете со своей анимацией, будет остановлено, если основной поток занят.

person Olexiy Burov    schedule 14.08.2015