Прежде всего, вопрос не очень ясен во многих аспектах. Если мое понимание верно, вы хотели, чтобы изменение границ автоматически перерисовывало CALayer во время анимации.
Способ первый:
Это может быть достигнуто общим способом, который включает в себя установку таймера и незначительное изменение границ (из массива CGRECT) и перерисовку каждый раз. Поскольку вы можете получить доступ к функции рисования, это не должно быть проблемой для разработки такой анимации самостоятельно.
Способ второй:
Идея та же, что и раньше, но если вы хотите использовать способ CAAnimation. следующий фрагмент может помочь вам.
В этом используется внешний таймер (CADisplayLink). Также изменение границ должно быть достигнуто с помощью функции updateBounds
для удобства.
Имейте в виду, структура фрагмента должна быть тщательно обработана. Любая модификация может привести к потере анимации.
Успешный результат покажет вам продолжение перерисовки во время изменения границ.
Проверка viewController:
class ViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
layer1 = MyLayer()
layer1.frame = CGRect.init(x: 0, y: 0, width: 300, height: 500)
layer1.backgroundColor = UIColor.red.cgColor
view.layer.addSublayer(layer1)
layer1.setNeedsDisplay()
}
@IBAction func updateLayer1(){
CATransaction.begin()
CATransaction.setAnimationDuration(3.0)
let nextBounds = CGRect.init(origin: layer1.bounds.origin, size: CGSize.init(width: layer1.bounds.width + 100, height: layer1.bounds.height + 150))
layer1.updateBounds(nextBounds)
CATransaction.commit()
}
}
Подкласс CALayer, перечисляющий только часть с анимацией изменения границ.
class MyLayer: CALayer, CAAnimationDelegate{
func updateBounds(_ bounds: CGRect){
nextBounds = bounds
self.bounds = bounds
}
private var nextBounds : CGRect!
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
if let keyPath = (anim as! CABasicAnimation).keyPath , let displayLink = animationLoops[keyPath]{
displayLink?.invalidate()
animationLoops.removeValue(forKey: keyPath) }
}
@objc func updateDrawing(displayLink: CADisplayLink){
bounds = presentation()!.bounds
setNeedsDisplay()
}
var animationLoops: [String : CADisplayLink?] = [:]
override func action(forKey event: String) -> CAAction? {
let result = super.action(forKey: event)
if(event == "bounds"){
guard let result = result as? CABasicAnimation,
animationLoops[event] == nil
else{return nil}
let anim = CABasicAnimation.init(keyPath: result.keyPath)
anim.fromValue = result.fromValue
anim.toValue = nextBounds
let caDisplayLink = CADisplayLink.init(target: self, selector: #selector(updateDrawing))
caDisplayLink.add(to: .main, forMode: RunLoop.Mode.default)
anim.delegate = self
animationLoops[event] = caDisplayLink
return anim
}
return result
}
Надеюсь, это то, что вы хотите. Хорошего дня.
Сравнение анимации:
Без таймера:
![enter image description here](https://i.stack.imgur.com/igH82.gif)
Добавление таймера CADsiaplayLinker:
![enter image description here](https://i.stack.imgur.com/etD35.gif)