我有一个带有自定义动画属性的UIView
子类,该属性与其他视图上的其他(内置)UIView
属性一起动画。我遇到的问题与这样一个事实有关:这个自定义属性在动画期间似乎与布局的其余部分略微不同步。
这是一个简单的例子来说明我的意思:
使用内置的transform
属性为蓝色方块设置动画,而红色方块在另一个(静止)UIView
内绘制,并由自定义属性drawFrame
设置动画。两个属性的动画匹配,从理论上讲,两个矩形应始终完全垂直对齐。
以下是上述示例的代码。要执行,只需启动一个新的Single View App项目并替换ViewController.swift
。
import UIKit
class ViewController: UIViewController {
let viewA = UIView(frame: CGRect(x: 50, y: 50, width: 100, height: 100))
let viewB = CustomAnimatedPropertyView(frame: CGRect(x: 50, y: 150, width: 200, height: 100))
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(viewA); viewA.backgroundColor = UIColor.blue
view.addSubview(viewB); viewB.backgroundColor = UIColor.clear
animate()
}
func animate() {
viewA.transform = CGAffineTransform.identity
viewB.drawFrame = CGRect(x: 0, y: 0, width: 100, height: 100)
UIView.animate(withDuration: 2.0, delay: 1.0, options: [], animations: {
self.viewA.transform = CGAffineTransform.identity.translatedBy(x: 100, y: 0.0)
self.viewB.drawFrame = CGRect(x: 100, y: 0, width: 100, height: 100)
})
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3) { self.animate() }
}
}
class CustomAnimatedPropertyView: UIView {
@objc dynamic var drawFrame: CGRect = CGRect.zero {
didSet {
guard let layer = layer as? CustomAnimatedPropertyLayer else { fatalError() }
layer.drawFrame = drawFrame
}
}
override public class var layerClass: AnyClass {
return CustomAnimatedPropertyLayer.self
}
override public func action(for layer: CALayer, forKey event: String) -> CAAction? {
if event == #keyPath(CustomAnimatedPropertyLayer.drawFrame),
let action = super.action(for: layer, forKey: #keyPath(backgroundColor)) as? CAAnimation,
let animation: CABasicAnimation = (action.copy() as? CABasicAnimation) {
animation.keyPath = #keyPath(CustomAnimatedPropertyLayer.drawFrame)
animation.fromValue = (layer as! CustomAnimatedPropertyLayer).drawFrame
animation.toValue = drawFrame
layer.add(animation, forKey: #keyPath(CustomAnimatedPropertyLayer.drawFrame))
return animation
}
return super.action(for: layer, forKey: event)
}
override func draw(_ layer: CALayer, in ctx: CGContext) {
guard let customLayer = layer as? CustomAnimatedPropertyLayer else { super.draw(layer, in: ctx); return }
ctx.setFillColor(UIColor.red.cgColor)
ctx.fill(customLayer.drawFrame)
usleep(20 * 1000) // <- To exacerbate the synchronization issue
}
}
class CustomAnimatedPropertyLayer: CALayer {
@NSManaged var drawFrame: CGRect
override class func needsDisplay(forKey key: String) -> Bool {
return super.needsDisplay(forKey: key) || key == #keyPath(drawFrame)
}
}
我已尝试很多的不同解决方案无济于事...我认为这可以使用CADisplayLink
或类似解决,但我更喜欢避免涉及重要代码重构的解决方案。
关于如何解决这个问题的任何想法?提前感谢您的任何答案。
答案 0 :(得分:1)
我认为你的问题没有通用的解决方案,动画的抽搐来自不同的类型。转换动画应该比标量值上的简单动画更复杂。
但是,我看到以下可能性摆脱了同步问题。我有几个替代建议。
transformation
财产翻译。您应该为两个图层使用通用的基本动画。不幸的是,我的提议非常普遍,但为了能够提供更具体的途径,我必须更多地了解具体问题。