CAShapeLayer странное поведение в первый раз анимации

Я написал эту анимацию для CAShapeLayer (pulseLayer) и в viewDidLoad():

let pulseLayer = CAShapeLayer()
@IBOutlet weak var btnCart: UIButton!

override func viewDidLoad() {
    let longpress = UILongPressGestureRecognizer(target: self, action: #selector(CategoryViewController.longPressGestureRecognized(_:)))
    tableView.addGestureRecognizer(longpress)

    heartBeatAnimation.duration       = 0.75
    heartBeatAnimation.repeatCount    = Float.infinity
    heartBeatAnimation.autoreverses   = true
    heartBeatAnimation.fromValue      = 1.0
    heartBeatAnimation.toValue        = 1.2
    heartBeatAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)

    btnCart.layer.addSublayer(pulseLayer)
}

func addBtnCartLayerWithAnimation() {
    let ovalPath = UIBezierPath(arcCenter: CGPoint(x: btnCart.frame.midX, y: btnCart.frame.midY), radius: btnCart.frame.width * 1.5, startAngle: 0*(CGFloat.pi / 180), endAngle: 360*(CGFloat.pi / 180), clockwise: true)

    pulseLayer.path = ovalPath.cgPath
    pulseLayer.opacity = 0.15
    pulseLayer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
    pulseLayer.bounds = ovalPath.cgPath.boundingBox
    pulseLayer.add(heartBeatAnimation, forKey: "heartBeatAnimation")
    pulseLayer.transform = CATransform3DScale(CATransform3DIdentity, 1.0, 1.0, 1.0)
}

и функция removeLayer:

func removeLayer() {
    pulseLayer.transform = CATransform3DScale(CATransform3DIdentity, 0.1, 0.1, 0.1)
    pulseLayer.removeAllAnimations()
}

Проблема в том, что первая анимация слоя идет снизу!

первая анимация после viewDidLoad

затем после этого любой вызов для этой анимации начинается с центра (определенной точки привязки)

любая анимация после первой

Кто-нибудь может сказать мне, почему это происходит?

весь класс, где я определил и использовал UILongGestureRecognizer на tableView для запуска / остановки анимации:

func longPressGestureRecognized(_ gestureRecognizer: UIGestureRecognizer) {
    let longPress = gestureRecognizer as! UILongPressGestureRecognizer
    let state = longPress.state
    let locationInView = longPress.location(in: tableView)
    let indexPath = tableView.indexPathForRow(at: locationInView)

    switch state {
    case UIGestureRecognizerState.began:
        if indexPath != nil {
            addBtnCartLayerWithAnimation()
        }

    case UIGestureRecognizerState.changed:
        // some code here not related to the animation 
    default:
        removeLayer()
    }
}

1 ответ

При использовании автономных слоев (слоев, которые не являются резервным хранилищем UIView), неявные анимации добавляются для каждого анимируемого изменения свойства.

Вы видите этот эффект, потому что слой анимирует свои свойства от нуля до начальных значений, которые вы устанавливаете в addBtnCartLayerWithAnimation(),

Что вы хотите сделать, это установить эти начальные значения без анимации (что должно быть сделано явно). Вы можете обернуть изменение в транзакции, в которой вы отключаете анимацию, следующим образом:

CATransaction.begin()
CATransaction.setDisableActions(true)

pulseLayer.path = ovalPath.cgPath
pulseLayer.opacity = 0.15
pulseLayer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
pulseLayer.bounds = ovalPath.cgPath.boundingBox
pulseLayer.transform = CATransform3DScale(CATransform3DIdentity, 1.0, 1.0, 1.0)

CATransaction.commit()

pulseLayer.add(heartBeatAnimation, forKey: "heartBeatAnimation")
Другие вопросы по тегам