How to specify an beginTime for an animation by using CFTimeInterval? - ios

For my understanding, beginTime can be used to say "hey, start at exactly 12:00 'o clock". But how would I tell this with an CFTimeInterval type? I thought that this one is nothing more than a kind of "float" value to specify seconds.
Or what else would be then the difference to the timeOffset property that is specified in CAMediaTiming protocol?

What I missed in the docs: beginTime is in "core animation absolute time" so you've to get the current time and specify your offset from that:
// Start in 5 seconds
theAnimation.beginTime = CACurrentMediaTime() + 5;

You first need to convert to the layer's timespace like so:
let currentLayerTime = myLayer.convertTime(CACurrentMediaTime(), from: nil)
Then you can set the beginTime relative to the layer's now time. For instance, to make an animation begin in 2s:
myAnimation.beginTime = currentLayerTime + 2
You'll also likely want to set the fillMode to .backwards, so that you can set the final property value before you add the animation:
myAnimation.fillMode = .backwards
myLayer.someProperty = someFinalValue
myLayer.addAnimation(myAnimation, forKey: "myAnimationName")

No, that is not what beginTime does. It specifies a relative start time from its parent animation (by default multiple animations in a group all fire at once).
From the documentation:
Specifies the begin time of the
receiver in relation to its parent
object, if applicable.
timeOffset causes it to start animating at the frame it would be at at the offSet time, and when it reaches the end it loops around. In other words, imagine A,B,C,D,E are frames of animation this is what happends in various cases if you set beginTime or timeOffset to a value equal to when you hit frame C in the normal case.
Normal |A->B->C->D->E
beginTime: | A->B->C->D->E
timeOffset: |C->D->E->A->B

I think the documentation of CAMediaTiming Protocol is very bad. Time Warp in Animation is a thorough explanation(re-documentation) of all properties of CAMediaTiming Protocol.

Related

How to implement countdown function like Yahoo's APP News Digest

I can use CAShapeLayer and UIBezierPath to draw the circle, I can also use this property CAShapeLayer.strokeEnd to control the progress. But the fast scrolling of path and time , I do not know how to implement.
Now I think the approach is to calculate the time difference between the two , and then use the time difference to circulation .
For example, The time difference between the two is 1000 seconds , should I have to set strokeEnd and the middle of the Label 1000 cycles ? Or that implement good results it ?
thanks in advance!
Note : StrokeEnd accepts value between 0 - 1
Lets Say,
See in your case circle represents the remaining time it will take to appear new feed. lets say 3PM.
so 3 PM will be your nextFeedTime = 3PM and,
you got this feed at 12PM so feedTime = 12PM.
So now you will have start and end value of feedTime=12PM - nextFeedTime=3PM
So feedTime is 0 for strokeEnd and nextFeedTime is 1 for StrokeEnd.
When you open app you will got currentTime which is initially initialised with feedTime and later it will be replaced all the time with current time stamp.
Lets assume currentTime is 1 PM.
Now we can calculate ratio to animate strockEnd property
strokeEnd = currentTime / nextFeedTime
and animate strokeEnd accordingly. hope this will helps you!

How to get the same time the update(currentTime:) function uses? (before it is called)

Question: The update(currentTime:) function in SKScene is called every frame with a currentTime argument. I'm wondering how to get the time from the same source update(currentTime:) uses without using the update function. I only found CFAbsoluteTimeGetCurrent() which is different.
Reason: To calculate timeSinceLastUpdate you need an instance variable called timeOfLastUpdate. To implement timeOfLastUpdate you need to set it to an arbitrary value before the first update which makes the first calculation of timeSinceLastUpdate incorrect. You could have a simple if statement to detect this or use optionals but that is an unneeded branch which could be avoided if I just set timeOfLastUpdate in didMoveToView(view:). And that is what I'm trying to do.
The first timeSinceLastUpdate will always be different from the rest. Typically one stores the absolute time from the previous update call and subtracts it from the current call's time to get a timeSinceLastUpdate. If the previous time doesn't exist because you're on the first pass through the render loop — it's set to zero or infinity or negative something or whatever sentinel value you initialized it to, just set your timeSinceLastUpdate to some nominal value for getting started. Something like your frame interval (16.67 ms if you're going for 60 fps) would make sense — you don't want game code that depends on that time interval to do something wild because you passed it zero or some wildly huge value.
In fact, it's not a bad idea to have logic for normalizing your timeSinceLastUpdate to something sane in the event that it gets foo large — say, because your user paused and resumed the game. If you have game entities (such as GameplayKit agents) whose movement follows some sort of position += velocity * timeSinceLastUpdate model, you want them to move by one frame's worth of time when you resume from a pause, not take a five-minute pause times velocity and jump to hyperspace.
If you initialize your previous time to zero, subtract, and normalize to your expected frame interval, you'll cover both the starting and unpausing cases with the same code.
You could always use coalesce:
let deltaTime = currentTime - (previousTime ?? currentTime).
On first loop, your deltaTime is 0 (Should be this) after that, it is the change
Of course previousTime must be an optional for this to work

Moving a CALayer with position, not to and from values?

Is this a good way to use position to move a CALayer permanently? Do I really need a to and from value animation?
serveBlock2 = [CALayer layer];
serveBlock2.zPosition = 1;
[serveBlock2 setFrame:CGRectMake(screenBounds.size.height/2, 0, screenBounds.size.height/2, screenBounds.size.width)];
[serveBlock2 setOpacity:0.0f];
[serveBlock2 setBackgroundColor:[UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:0.8f].CGColor];
[self.view.layer addSublayer:serveBlock2];
CABasicAnimation *updateCurrentServe2 = [CABasicAnimation animationWithKeyPath:#"position.y"];
serveBlock2.position = CGPointMake((screenBounds.size.height/4)*3, -screenBounds.size.width/2);
[updateCurrentServe2 setTimingFunction:[CAMediaTimingFunction functionWithControlPoints:0.8 :-0.8 :1.0 :1.0]];
[updateCurrentServe2 setDuration:1.5];
[serveBlock2 addAnimation:updateCurrentServe2 forKey:#"serveBlock2 updateCurrentServe2"];
It isn't clear what you are asking.
Core Animation does not actually move the position of the layers it animates. It creates the appearance that the layer is changing (by making changes to the layer's presentation layer) but does not actually change the underlying property. Usually what you do is to start the animation running, then add extra statements to set the property/properties you are changing to their end values. Then when the animation completes the object is in it's final location.
When you create a CAAnimation, you can supply a from and to value or just a to value. If you only provide a to value, it will animate from it's previous position to the new position.
If you just want to move your layer, set it's position property without an animation.
If the layer is the backing layer of a view, it will simply jump to it's new location.
If the layer is some other sublayer, you will get an implicit animation from the old value to the new value.
You have two questions there and I will answer them in the opposite order:
Do I really need a to and from value animation?
No, you don't need that.
CABasicAnimation has three properties that go together define how the interpolation is done, these are fromValue, byValue and toValue. They can be combined in many different ways which is listed under the "Setting Interpolation Values" section in the CABasicAnimation documentation. The very last listed combination is:
All properties are nil. Interpolates between the previous value of keyPath in the target layer’s presentation layer and the current value of keyPath in the target layer’s presentation layer.
So what you are doing and the results you are seeing is documented behavior and works.
Is this a good way to use position to move a CALayer permanently?
This is a very opinionated question and I can only give you my personal opinion and try and explain my reasoning.
I personally don't like it because it is less explicit and you would need to have read this special case in the documentation to know how it works. As you saw in the comment on your question I wasn't even sure how this worked when I first saw it and I consider myself very familiar with Core Animation and have read the documentation many times.
It all should come down to what you and your team thinks is most readable and clear.
Personally I prefer to explicitly set the new model value and then only specify the fromValue, i.e. this case:
fromValue is non-nil. Interpolates between `fromValue and the current presentation value of the property.

CAKeyframeAnimation - animate along segment of a path

I'm trying to animate an object along a specific segment of a path using CAKeyframeAnimation. Is this possible?
Think of a path as parameterized between 0 and 1, which is what an animation will typically run on (from the start of the curve to the end of the curve). Is there a way I can run an animation, say, from .25 to .75 of this path?
I know I can offset an animation with the 'offset' parameter, but this only adjusts the start position and still loops around to the end of the curve. It also doesn't correctly obey the CAMediaTiming function, if set.

UIModalTransitionStyleFlipHorizontal animation duration?

What is the default value of (NSTimeInterval)duration for UIModalTransitionStyleFlipHorizontal, which is related to -[UIViewController presentModalViewController:animated:]?
If you are asking what the default value of the duration is on an animation when you do not explicitly set it, the answer is provided in the framework headers:
* If the `duration' property of the animation is zero or negative it
* is given the default duration, either the value of the
* `animationDuration' transaction property or .25 seconds otherwise.
So, since you can't set the value on the method call, it should take a quarter second to execute the animation.

Resources