I've wrote this animation to the CAShapeLayer (pulseLayer) and in the 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)
}
and the removeLayer function is:
func removeLayer() {
pulseLayer.transform = CATransform3DScale(CATransform3DIdentity, 0.1, 0.1, 0.1)
pulseLayer.removeAllAnimations()
}
The problem is when the first animation of the layer is coming from the bottom of the view !
the first animation after viewDidLoad
then after that any invoke for this animation with start from the center(the defined anchor point)
any animation after the first one
Could anyone tell me why this happening ?
the whole class where I defined and used UILongGestureRecognizer
on tableView to start/stop the animation :
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()
}
}
When using standalone layers (layers that are not the backing store of a
UIView
), implicit animations are added for every animatable property change.You're seeing this effect because the layer is animating its properties from zero to the initial values you're setting in
addBtnCartLayerWithAnimation()
.What you want to do is to set these initial values without animation (which needs to be done explicitly). You can wrap the change in a transaction in which you disable animations like so: