如何正确设置 CABasicAnimation(开始)时间?
How to properly set the CABasicAnimation (begin) time?
我使用 CABasicAnimation 对存储在数组中的 CAShapeLayers
的颜色进行动画处理。动画根据 animation.duration
不规律地显示,我不知道为什么。我怀疑 animation.beginTime = CACurrentMediaTime() + delay
有问题
动画说明
动画包括在动画结束后将形状依次闪烁为黄色,然后将其变为黑色。
动画的当前状态
当动画持续时间超过一定时间时,它会正常工作。
- 例如,持续时间为 2 秒:
但是当我缩短持续时间时,结果大不相同。
- 例如,持续时间为1秒:
您会注意到动画已经 cached/ended 前 10 个左右的小节,然后等待并开始为其余形状设置动画。
- 同理,持续时间为0.5s:
在这种情况下,在一定时间后显示一些动画之前,似乎有更多的动画已经结束(形状为黑色)。您还可以注意到,虽然形状颜色动画应该持续相同的持续时间 (0.5s),但有些感觉比其他动画更快。
代码
动画是在UIViewController的viewDidAppear方法中调用的class.
我创建了一个 UIView 自定义 class 来绘制我的形状,并使用 class.
的扩展为它们制作动画
设置颜色动画的代码:
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:
()
}
}
根据颜色变化的持续时间来分割整个动画的持续时间(例如如果整个动画是10s,每个形状在1s内变色,则表示10个形状会变色)。
然后我使用方法 colorAnimation(for: fromColor, toColor, startAfter:).
创建 CABasicaAnimation 对象
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 中。
代码显然可以优化,但我选择继续执行这些步骤以尝试找出它无法正常工作的原因。
目前尝试次数
到目前为止,我已经尝试过:
在 colorAnimation 方法中有和没有设置 animation.beginTime
,包括有和没有 CACurrentMediaTime()
:如果我没有设置 animation.beginTime
和 CACurrentMediaTime
,我根本看不到任何动画。
有和没有指向animation.delegate = self
:它没有改变任何东西。
使用 DispatchQueue(将动画存储在 global 中,运行 将其存储在 main 中)并且怀疑形状没有动画。
我怀疑 beginTime 无法正常工作,但情况可能并非如此,或者只是因为即使在形状动画时,形状动画持续时间似乎有所不同,但实际上应该不会。
非常感谢能看到这个问题。欢迎任何想法,即使它看起来很牵强,它可以开辟解决这个问题的新方法!
最佳,
其实duration和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
,部分band会双动
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))
我使用 CABasicAnimation 对存储在数组中的 CAShapeLayers
的颜色进行动画处理。动画根据 animation.duration
不规律地显示,我不知道为什么。我怀疑 animation.beginTime = CACurrentMediaTime() + delay
动画说明
动画包括在动画结束后将形状依次闪烁为黄色,然后将其变为黑色。
动画的当前状态
当动画持续时间超过一定时间时,它会正常工作。
- 例如,持续时间为 2 秒:
但是当我缩短持续时间时,结果大不相同。
- 例如,持续时间为1秒:
您会注意到动画已经 cached/ended 前 10 个左右的小节,然后等待并开始为其余形状设置动画。
- 同理,持续时间为0.5s:
在这种情况下,在一定时间后显示一些动画之前,似乎有更多的动画已经结束(形状为黑色)。您还可以注意到,虽然形状颜色动画应该持续相同的持续时间 (0.5s),但有些感觉比其他动画更快。
代码
动画是在UIViewController的viewDidAppear方法中调用的class.
我创建了一个 UIView 自定义 class 来绘制我的形状,并使用 class.
的扩展为它们制作动画设置颜色动画的代码:
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:
()
}
}
根据颜色变化的持续时间来分割整个动画的持续时间(例如如果整个动画是10s,每个形状在1s内变色,则表示10个形状会变色)。 然后我使用方法 colorAnimation(for: fromColor, toColor, startAfter:).
创建 CABasicaAnimation 对象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 中。 代码显然可以优化,但我选择继续执行这些步骤以尝试找出它无法正常工作的原因。
目前尝试次数
到目前为止,我已经尝试过:
在 colorAnimation 方法中有和没有设置
animation.beginTime
,包括有和没有CACurrentMediaTime()
:如果我没有设置animation.beginTime
和CACurrentMediaTime
,我根本看不到任何动画。有和没有指向
animation.delegate = self
:它没有改变任何东西。使用 DispatchQueue(将动画存储在 global 中,运行 将其存储在 main 中)并且怀疑形状没有动画。
我怀疑 beginTime 无法正常工作,但情况可能并非如此,或者只是因为即使在形状动画时,形状动画持续时间似乎有所不同,但实际上应该不会。
非常感谢能看到这个问题。欢迎任何想法,即使它看起来很牵强,它可以开辟解决这个问题的新方法!
最佳,
其实duration和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
,部分band会双动
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))