Как правильно установить время CABasicAnimation (начало)? - PullRequest
0 голосов
/ 01 февраля 2019

Я анимирую цвет CAShapeLayers, хранящийся в массиве, используя CABasicAnimation.Анимация отображается неустойчиво в зависимости от animation.duration, и я не могу понять, почему.Я подозреваю, что проблема с animation.beginTime = CACurrentMediaTime() + delay

Описание анимации

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

Текущее состояние анимации

Когда продолжительность анимации превышает определенное время, она работает правильно.

  • Например, спродолжительность 2 секунды:

2-second animation

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

  • Например, с продолжительностью 1 секунда:

1-second animation:

Вы заметите, что анимация имеетуже кэширован / закончен для первых 10 тактов или около того, затем ждет и начинает анимировать оставшуюся часть фигур.

  • Аналогично, с длительностью 0,5 с:

0.5s animation

В этом случае, кажется, еще большее количество анимации ужеded (фигуры черного цвета), прежде чем он отобразит анимацию через определенное время.Вы также можете заметить, что, хотя цветовая анимация формы должна длиться одинаково (0,5 с), некоторые чувствуют себя быстрее, чем другие.

Код

Анимация вызывается в методе viewDidAppear класса UIViewController.

Я создал пользовательский класс UIView для рисования своих фигур и анимировал их, используя расширение класса.

Код для анимации цвета:

    enum ColorAnimation{
        case continuousSwap
        case continousWithNewColor(color: UIColor)
        case randomSwap
        case randomWithNewColor(color: UIColor)
        case randomFromUsedColors
    }


    func animateColors(for duration: Double,_ animationType: ColorAnimation, colorChangeDuration swapColorDuration: Double){
        guard abs(swapColorDuration) != Double.infinity else {
            print("Error in defining the shape color change duration")
            return
        }
        let animDuration = abs(duration)
        let swapDuration = abs(swapColorDuration)
        let numberOfSwaps = Int(animDuration / min(swapDuration, animDuration))


        switch animationType {
        case .continousWithNewColor(color: let value):
            var fullAnimation = [CABasicAnimation]()
            for i in (0...numberOfSwaps) {
                let index = i % (self.pLayers.count)
                let fromValue = pLayers[index].pattern.color
                let delay =  Double(i) * swapDuration / 3
                let anim = colorAnimation(for: swapDuration, fromColor: value, toColor: fromValue, startAfter: delay)
                fullAnimation.append(anim)
            }

            for i in (0...numberOfSwaps) {
                CATransaction.begin()
                 let index = i % (self.pLayers.count)
                CATransaction.setCompletionBlock {
                    self.pLayers[index].shapeLayer.fillColor = UIColor.black.cgColor
                }
                pLayers[index].shapeLayer.add(fullAnimation[i], forKey: "fillColorShape")
                CATransaction.commit()
            }
        default:
            ()
        }
    }

Сегментирует всю продолжительность анимации по продолжительности изменения цвета ( например, , если вся анимация равна 10 с и каждая фигура меняет цветв 1 с, это означает, что 10 фигур будут менять цвет).Затем я создаю объекты CABasicaAnimation с помощью метода colorAnimation (for: fromColor, toColor, startAfter:).

func colorAnimation(for duration: TimeInterval, fromColor: UIColor, toColor: UIColor, reverse: Bool = false, startAfter delay: TimeInterval) -> CABasicAnimation {
        let anim = CABasicAnimation(keyPath: "fillColor")
        anim.fromValue = fromColor.cgColor
        anim.toValue = toColor.cgColor
        anim.duration = duration
        anim.autoreverses = reverse
        anim.beginTime = CACurrentMediaTime() + delay
        return anim
    }

Наконец, я добавляю анимацию к соответствующему CAShapeLayer.Код, очевидно, можно оптимизировать, но я решил пойти по этим шагам, чтобы попытаться выяснить, почему он не работает должным образом.

Пока предпринимаются попытки

Пока что япробовал:

  • с и без установки animation.beginTime в методе colorAnimation, в том числе с и без CACurrentMediaTime(): если я не установил animation.beginTime с CACurrentMediaTimeЯ просто не вижу никакой анимации.

  • с указанием и без указания animation.delegate = self: ничего не изменилось.

  • с использованием DispatchQueue (сохраните анимацию в глобальном и запустите ее в основном), и, как подозревалось, фигуры не анимировались.

Я подозреваю, что что-то не работает должным образом с beginTime, но это может быть не такили только потому, что даже когда фигуры анимируются, продолжительность анимации фигуры может меняться, хотя и не должна.

Заранее большое спасибо, чтобы взглянуть на эту проблему.Любые мысли приветствуются, даже если они кажутся надуманными, они могут открыть новые способы решения этой проблемы!

Best,

1 Ответ

0 голосов
/ 01 февраля 2019

На самом деле существует связь между продолжительностью и swapColorDuration

func animateColors(for duration: Double,_ animationType: ColorAnimation, colorChangeDuration swapColorDuration: Double)

, когда вы звоните, вам может понадобиться сохранить эту связь

    let colorChangeDuration: TimeInterval = 0.5
    animateColors(for: colorChangeDuration * TimeInterval(pLayers.count), .continousWithNewColor(color: UIColor.black), colorChangeDuration: colorChangeDuration)

Также здесь:

 let numberOfSwaps = Int(animDuration / min(swapDuration, animDuration)) - 1

Это значение может быть немного выше, чем вам нужно.

или

Проблема заключается в этом let index = i % (self.pLayers.count)

if numberOfSwaps > self.pLayers.countнекоторые группы будут иметь двойную анимацию.

 let numberOfSwaps1 = Int(animDuration / min(swapDuration, animDuration))
 let numberOfSwaps = min(numberOfSwaps1, self.pLayers.count)

, в остальных -

       for i in (0..<numberOfSwaps) {... }

Теперь, если numberOfSwaps < self.pLayers.count.Это не закончено.

, если numberOfSwaps больше, это нормально.

Если требуется двойная анимация, измените следующее:

pLayers[index].shapeLayer.add(fullAnimation[i], forKey: nil)

или pLayers[index].shapeLayer.add(fullAnimation[i], forKey: "fillColorShape" + String(i))

...