我目前正在使用AVMutableComposition在视频中叠加一些文本,我想根据某个时间间隔重复更改字符串。我正在尝试使用核心动画来实现这一目标;但是,string属性似乎无法设置动画。还有其他方法可以实现目标吗?谢谢。
代码(不起作用):
func getSubtitlesAnimation(withFrames frames: [String], duration: CFTimeInterval)->CAKeyframeAnimation {
let animation = CAKeyframeAnimation(keyPath:"string")
animation.calculationMode = kCAAnimationDiscrete
animation.duration = duration
animation.values = frames
animation.keyTimes = [0,0.5,1]
animation.repeatCount = Float(frames.count)
animation.isRemovedOnCompletion = false
animation.fillMode = kCAFillModeForwards
animation.beginTime = AVCoreAnimationBeginTimeAtZero
return animation
}
答案 0 :(得分:3)
字符串不是CATextLayer上的动画路径。这是list of keyPaths,您可以在任何CALayer上使用。
关于将Core Animation与AVFoundation一起使用的其他一些重要事项。
Example1Using-Discrete
import UIKit
class ViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
//center the frame
let textFrame = CGRect(x: (self.view.bounds.width - 200)/2, y: (self.view.bounds.height - 100)/2, width: 200, height: 50)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()) {
//animation spacing could be a negative value of half the animation to appear to fade between strings
self.animateText(subtitles: ["Hello","Good Morning","Good Afternoon","Good Evening","Goodnight","Goodbye"], duration: 2, animationSpacing: 0, frame: textFrame, targetLayer: self.view.layer)
}
}
func animateText(subtitles:[String],duration:Double,animationSpacing:Double,frame:CGRect,targetLayer:CALayer){
var currentTime : Double = 0
for x in 0..<subtitles.count{
let string = subtitles[x]
let textLayer = CATextLayer()
textLayer.frame = frame
textLayer.string = string
textLayer.font = UIFont.systemFont(ofSize: 20)
textLayer.foregroundColor = UIColor.black.cgColor
textLayer.fontSize = 20.0
textLayer.alignmentMode = kCAAlignmentCenter
let anim = getSubtitlesAnimation(duration: duration, startTime: currentTime)
targetLayer.addSublayer(textLayer)
textLayer.add(anim, forKey: "opacityLayer\(x)")
currentTime += duration + animationSpacing
}
}
func getSubtitlesAnimation(duration: CFTimeInterval,startTime:Double)->CAKeyframeAnimation {
let animation = CAKeyframeAnimation(keyPath:"opacity")
animation.duration = duration
animation.calculationMode = kCAAnimationDiscrete
//have to fade in and out with a single animation because AVFoundation
//won't allow you to animate the same propery on the same layer with
//two different animations
animation.values = [0,1,1,0,0]
animation.keyTimes = [0,0.001,0.99,0.999,1]
animation.isRemovedOnCompletion = false
animation.fillMode = kCAFillModeBoth
//Replace with AVCoreAnimationBeginTimeAtZero for AVFoundation
animation.beginTime = CACurrentMediaTime() + startTime
return animation
}
}
示例2-使用带有较长淡入效果的Gif附件
import UIKit
class ViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
//center the frame
let textFrame = CGRect(x: (self.view.bounds.width - 200)/2, y: (self.view.bounds.height - 100)/2, width: 200, height: 50)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()) {
//animation spacing could be a negative value of half the animation to appear to fade between strings
self.animateText(subtitles: ["Hello","Good Morning","Good Afternoon","Good Evening","Goodnight","Goodbye"], duration: 4, animationSpacing: -2, frame: textFrame, targetLayer: self.view.layer)
}
}
func animateText(subtitles:[String],duration:Double,animationSpacing:Double,frame:CGRect,targetLayer:CALayer){
var currentTime : Double = 0
for x in 0..<subtitles.count{
let string = subtitles[x]
let textLayer = CATextLayer()
textLayer.frame = frame
textLayer.string = string
textLayer.font = UIFont.systemFont(ofSize: 20)
textLayer.foregroundColor = UIColor.black.cgColor
textLayer.fontSize = 20.0
textLayer.alignmentMode = kCAAlignmentCenter
let anim = getSubtitlesAnimation(duration: duration, startTime: currentTime)
targetLayer.addSublayer(textLayer)
textLayer.add(anim, forKey: "opacityLayer\(x)")
currentTime += duration + animationSpacing
}
}
func getSubtitlesAnimation(duration: CFTimeInterval,startTime:Double)->CAKeyframeAnimation {
let animation = CAKeyframeAnimation(keyPath:"opacity")
animation.duration = duration
//have to fade in and out with a single animation because AVFoundation
//won't allow you to animate the same propery on the same layer with
//two different animations
animation.values = [0,0.5,1,0.5,0]
animation.keyTimes = [0,0.25,0.5,0.75,1]
animation.isRemovedOnCompletion = false
animation.fillMode = kCAFillModeBoth
//Replace with AVCoreAnimationBeginTimeAtZero for AVFoundation
animation.beginTime = CACurrentMediaTime() + startTime
return animation
}
}
答案 1 :(得分:1)
Swift 5解决方案:
喜欢@ agibson007的答案
在0.25的持续时间内无法进行优化。 (存在褪色/闪烁的问题)
func animateText(subtitles:[String],duration:Double,animationSpacing:Double,frame:CGRect,targetLayer:CALayer){
var currentTime : Double = 0
for x in 0..<subtitles.count{
let textLayer = CATextLayer()
textLayer.frame = frame
textLayer.string = subtitles[x]
textLayer.font = UIFont.systemFont(ofSize: 20)
textLayer.foregroundColor = UIColor.black.cgColor
textLayer.fontSize = 40.0
textLayer.alignmentMode = .center
let anim = getSubtitlesAnimation(duration: duration, startTime: currentTime)
textLayer.add(anim, forKey: "opacityLayer\(x)")
targetLayer.addSublayer(textLayer)
currentTime += duration + animationSpacing
}
}
func getSubtitlesAnimation(duration: CFTimeInterval,startTime:Double)->CAKeyframeAnimation {
let animation = CAKeyframeAnimation(keyPath:"opacity")
animation.duration = duration
animation.calculationMode = .discrete
animation.values = [0,1,1,0,0]
animation.keyTimes = [0,0.00000001,0.999,0.999995,1]
animation.isRemovedOnCompletion = false
animation.fillMode = .both
animation.beginTime = AVCoreAnimationBeginTimeAtZero + startTime // CACurrentMediaTime() <- NO AV Foundation
return animation
}
let steps = 0.25
let duration = 8.0
let textFrame = CGRect( x: (videoSize.width / 2) - (90 / 2) , y: videoSize.height * 0.2, width: 90, height: 50)
var subtitles:[String] = []
for i in 0...Int(duration / steps) {
let time = i > 0 ? steps * Double(i) : Double(i)
subtitles.append(String(format: "%0.1f", time) )
}
animateText(subtitles: subtitles, duration: steps, animationSpacing: 0, frame: textFrame, targetLayer: layer)
答案 2 :(得分:1)
使用 CATextLayer 和 CAKeyframeAnimation 的文本动画解决方案。现在 string 属性是可动画的。不知道过去怎么样。
func addTextLayer(to layer: CALayer) {
let myAnimation = CAKeyframeAnimation(keyPath: "string");
myAnimation.beginTime = 0;
myAnimation.duration = 1.0;
myAnimation.values = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"]
myAnimation.fillMode = CAMediaTimingFillMode.forwards;
myAnimation.isRemovedOnCompletion = false;
myAnimation.repeatCount = 1;
let textLayer = CATextLayer();
textLayer.frame = CGRect(x: 200, y: 300, width: 100, height: 100);
textLayer.string = "0";
textLayer.font = UIFont.systemFont(ofSize: 20)
textLayer.foregroundColor = UIColor.black.cgColor
textLayer.fontSize = 40.0
textLayer.alignmentMode = .center
textLayer.add(myAnimation, forKey: nil);
layer.addSublayer(textLayer);
}
答案 3 :(得分:0)
尝试思考电影中如何添加字幕?
字幕文件包含时间戳记值,例如00:31:21:“某些文本”。因此,当电影的搜索栏位于00:31:21时,您会看到“某些文本”作为字幕。
类似地,根据您的要求,您将需要多个CATextLayers
,它们具有与它们相对应的动画(每个CATExtLayer相同或不同)。当一个CATextLayer动画结束时,您可以淡入第二个CATextLayer,淡入第一个。
我记得上一次这样做,可以对动画进行分组,并且您实际上可以指定动画的起点。检查beginTime
的{{1}}属性