Я пытаюсь экспортировать видеофайл с наложением CALayer
и несколькими вложенными CAAnimation
, связанными со временем. Для этого я использую AVVideoCompositionCoreAnimationTool
.
Мои CABasicAnimation
объединены в цепочку путем смещения их beginTime
.
Внутри animationDidStop(_:finished:)
я обновляю анимированное свойство соответствующего CALayer
.
Я удалил большую часть шаблона из примера кода ниже ...
/* AnimationChainer is A simple class whose instance will
* update a CALayer's model to reflect the final state of
* the animation. a translation on the y-axis in this case. */
class AnimationChainer: NSObject, CAAnimationDelegate {
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
let val = anim.value(forKey: "yTranslation") as! CGFloat
let layer = anim.value(forKey: "layer") as! CALayer
CATransaction.begin()
CATransaction.setDisableActions(true)
layer.transform = CATransform3DMakeTranslation(0.0, val, 0.0)
CATransaction.commit()
}
}
/* animation setup - a layer going up by 200pt then back to original pos. */
let chainer: AnimationChainer!
let interval = 2
let movingLayer = CALayer()
let translateOnceAnimation = CABasicAnimation(keyPath: "transform.translation.y")
translateOnceAnimation.duration = 0.4
translateOnceAnimation.fromValue = 0
translateOnceAnimation.byValue = -200
translateOnceAnimation.isRemovedOnCompletion = false
translateOnceAnimation.fillMode = .forwards
translateOnceAnimation.setValue(-200, forKey: "yTranslation")
translateOnceAnimation.setValue(movingLayer, forKey: "layer")
translateOnceAnimation.delegate = chainer
translateOnceAnimation.beginTime = AVCoreAnimationBeginTimeAtZero
let translateTwiceAnimation = CABasicAnimation(keyPath: "transform.translation.y")
translateTwiceAnimation.duration = 0.4
translateTwiceAnimation.fromValue = -200
translateTwiceAnimation.byValue = 200
translateTwiceAnimation.isRemovedOnCompletion = false
translateTwiceAnimation.fillMode = .forwards
translateTwiceAnimation.setValue(0.0, forKey: "yTranslation")
translateTwiceAnimation.setValue(movingLayer, forKey: "layer")
translateTwiceAnimation.delegate = chainer
translateTwiceAnimation.beginTime = AVCoreAnimationBeginTimeAtZero + interval
movingLayer.add(translateOnceAnimation, forKey: nil)
movingLayer.add(translateTwiceAnimation, forKey: nil)
let parentLayer = CALayer()
parentLayer.addSublayer(movingLayer)
/* end of animation setup */
let compo: AVMutableComposition!
let videoCompo: AVMutableVideoComposition!
let videoLayer: CALayer!
videoCompo.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, in: parentLayer)
let exporter = AVAssetExportSession(asset: compo, presetName: AVAssetExportPresetHighestQuality)
exporter?.videoComposition = videoCompo
exporter?.exportAsynchronously {
self.exportDidFinish(exporter!)
}
Это хорошо работает, когда я связываю анимированный слой в корневом представлении контроллера представления.
Но всякий раз, когда я использую его с AVVideoCompositionCoreAnimationTool
, вызывается animationDidStop(_:finished:)
, но в случайном порядке.
В результате неверное конечное состояние для анимированного свойства.
Самое странное, что если я поставлю точку останова внутри animationDidStop(_:finished:)
, это сработает!
Еще один тревожный результат: если я удаляю делегатов, он все еще работает ... вероятно, из-за fillMode. но я не могу объяснить это полностью.