I manage to animate an CALayer along a UIBezierPath.
What i'm trying to accomplish is to animate only a percentage of the path, for example, only 25% of the path, with the layer staying at that position (at 25%).
What is the way to do this? Here is my code, it always animate the full path.
let aPath = UIBizierPath(CGPath: somePath)
let anim = CAKeyframeAnimation(keyPath: "position")
anim.path = aPath.CGPath
anim.rotationMode = kCAAnimationRotateAuto
anim.repeatCount = 1
anim.fillMode = kCAFillModeForwards
anim.removedOnCompletion = false
anim.duration = 3.0
anim.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
ticker.addAnimation(anim, forKey: "animate_ticker")
Simple change one property:
anim.repeatCount = 0.25
Here is an excellent article on animation timing,you can learn how to have even more fine-grained control over your animations.
Append:
1. To achieve what you want ,the closest way is to have an 25% subPath ,here is some helper method.
2.If you can stand the speed difference,Use the method above, and set back the position when animation ends:
ticker.position = ticker.presentationLayer().position
Not only CGPath
is opaque, but also CAAnimation
doesn't support any updates or notifications for ongoing animations (i.e. after started but before finished). The only entities involved are animation itself and CALayer
-s it is applied to.
So, options are:
(some options may sound too scary but they are not, so I made an example project, see below)
As wj2061 mentioned is his answer you can tweak animation's repeatCount
. Cons is it will animate 0.25 of animation time, not 0.25 of path
If, by any chance, you can represent your ticker
with CAShapeLayer
segment then you can animate strokeStart
and strokeEnd
so it will look like segment is moving along the path
You can calculate such repeatCount
value that animation will stop at 0.25 of path.
getControlPointAtIndex:
t
) for which bezier's 'y' value will match to your "required progress" (0.25)t
- this is exact value of repeatCount
you needkind of advanced
rideProgress
rideLayer
) to animateneedsDisplayForKey:
for rideProgress
key and initWithLayer:
for all introduced properties BUT use self.rideLayer?.presentationLayer()
instead of copying rideLayer
drawInContext:
and draw what you need in it; or (better) display
, in display
retrieve current rideProgress
value from presentationLayer
and update sublayer, then call super. Either way, use bezier lib to calculate position and rotation for sublayer accordingly to current rideProgress
valueCATransaction.setDisableActions(true)
before setting any animatable property of any layerrideProgress
propertyAgain, suggested by wj2061. You can split the path so one of halves will represent 0.25 of original
Here is example implementation of everything above EXCEPT "Split path". I didn't run any field tests on this code, it's just a working concept. XCode 7.3.1, Swift.
Materials used: Wiki on Cubic function, Great article about operations on beziers, Cubic equations solving method line-by-line
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With