I have a cycle animate in viewController
- (void)moveAnimating
{
[UIView animateWithDuration:2.0f animations:^{
_backgroundView.center = CGPointMake(self.center.x , self.center.y - kMoveDistanceHeight);
} completion:^(BOOL finished) {
if (_backgroundView.animating)
{
[_backgroundView moveAnimating];
}
}];
}
I want stop this animate When the viewController viewWillDisappear:
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
_backgroundView.animating = NO;
[_backgroundView.layer removeAllAnimations];
}
Because the animation is conflict with dismissViewcontrollerAnimation.
Question:
[_backgroundView.layer removeAllAnimations];
not work...
How to stop the animation?
Help me,thanks.
You are canceling animations correctly:
[_backgroundView.layer removeAllAnimations];
But you might forget about importing QuartzCore.h:
#import <QuartzCore/QuartzCore.h>
If it doesn't help try this:
[CATransaction begin];
[_backgroundView.layer removeAllAnimations];
[CATransaction commit];
If it doesn't help try to add this line to the code above:
[CATransaction flush];
Te solution from #KlimczakM didn't work for me.
I'm running an 'animateWithDuration' block that moves and image, and I use the next code to pause and resume the animation:
-(void)pauseLayer:(CALayer*)layer {
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
layer.speed = 0.0;
layer.timeOffset = pausedTime;
}
-(void)resumeLayer:(CALayer*)layer {
CFTimeInterval pausedTime = [layer timeOffset];
layer.speed = 1.0;
layer.timeOffset = 0.0;
layer.beginTime = 0.0;
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
layer.beginTime = timeSincePause;
}
This is from the Apple Documentation at this link.
Related
I have an animation with 5.0 second duration. While an animation is being played, i pause it at 2.0 second and do some other things (moving to other viewcontroller, push, pop...). And then i back to this viewcontroller and continue animation from second 2.0. I made it work smooth with timeOffSet = 2.0, but still have an issue : It has 2 seconds surplus, that is the first 2 second of an animation.....How can i remove it ?
Animation with timeOffSet process:
Duplicated answer
-(void)pauseLayer:(CALayer*)layer
{
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
layer.speed = 0.0;
layer.timeOffset = pausedTime;
}
-(void)resumeLayer:(CALayer*)layer
{
CFTimeInterval pausedTime = [layer timeOffset];
layer.speed = 1.0;
layer.timeOffset = 0.0;
layer.beginTime = 0.0;
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
layer.beginTime = timeSincePause;
}
Apple mentions these two methods for pausing and resuming a CALayer animation going on
-(void)pauseLayer:(CALayer*)layer {
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
layer.speed = 0.0;
layer.timeOffset = pausedTime;
}
-(void)resumeLayer:(CALayer*)layer {
CFTimeInterval pausedTime = [layer timeOffset];
layer.speed = 1.0;
layer.timeOffset = 0.0;
layer.beginTime = 0.0;
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
layer.beginTime = timeSincePause;
}
but how do I restart the animation?
this other SO question has nothing to do with what I need.
I have adopted code from blog in ViewController. Take a look at method [resetEmitterLayer:]. In your case all you need to do to reset animation is as follow:
Remove emitter layer from super layer.
Recreate emitter layer.
Add new emitter layer to the layer tree.
See ViewController implementation below
#import "EmitterViewController.h"
#import <QuartzCore/QuartzCore.h>
#interface EmitterViewController ()
#property (nonatomic, strong) CAEmitterLayer *emitterLayer;
#end
#implementation EmitterViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.emitterLayer = [self createEmitterLayer];
[self.view.layer addSublayer:self.emitterLayer];
}
-(CAEmitterLayer *)createEmitterLayer {
CAEmitterLayer *emitterLayer = [CAEmitterLayer layer];
emitterLayer.emitterPosition = CGPointMake(self.view.bounds.size.width / 2, self.view.bounds.origin.y);
emitterLayer.emitterZPosition = 10;
emitterLayer.emitterSize = CGSizeMake(self.view.bounds.size.width, 0);
emitterLayer.emitterShape = kCAEmitterLayerSphere;
CAEmitterCell *emitterCell = [CAEmitterCell emitterCell];
emitterCell.scale = 0.1;
emitterCell.scaleRange = 0.2;
emitterCell.emissionRange = (CGFloat)M_PI_2;
emitterCell.lifetime = 5.0;
emitterCell.birthRate = 10;
emitterCell.velocity = 200;
emitterCell.velocityRange = 50;
emitterCell.yAcceleration = 250;
emitterCell.contents = (id)[[UIImage imageNamed:#"WaterDrop.png"] CGImage];
emitterLayer.emitterCells = [NSArray arrayWithObject:emitterCell];
return emitterLayer;
}
-(IBAction)pauseEmitterLayer:(id)sender
{
CFTimeInterval pausedTime = [self.emitterLayer convertTime:CACurrentMediaTime() fromLayer:nil];
self.emitterLayer.speed = 0.0;
self.emitterLayer.timeOffset = pausedTime;
}
-(IBAction)resumeEmitterLayer:(id)sender
{
CFTimeInterval pausedTime = [self.emitterLayer timeOffset];
self.emitterLayer.speed = 1.0;
self.emitterLayer.timeOffset = 0.0;
self.emitterLayer.beginTime = 0.0;
CFTimeInterval timeSincePause = [self.emitterLayer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
self.emitterLayer.beginTime = timeSincePause;
}
-(IBAction)resetEmitterLayer:(id)sender
{
[self.emitterLayer removeFromSuperlayer];
self.emitterLayer = [self createEmitterLayer];
[self.view.layer addSublayer:self.emitterLayer];
}
#end
I have 3 CABasicAnimation of 3 color bars which is following each other. After the third is completed, 3 bars will stay at their final position. Until here, everything is good, here is the code:
- (void)animationDidStop:(CABasicAnimation *)theAnimation finished:(BOOL)flag {
NSString* value = [theAnimation valueForKey:#"id"];
if([value isEqualToString:#"position1"]){
[self playVideoAtIndex:1];
}
else if([value isEqualToString:#"position2"]){
[self playVideoAtIndex:2];
}
else if([value isEqualToString:#"position3"]){
}
}
Before that, I created 3 animations like this:
-(void)createAnimationAtIndex:(NSInteger)index{
UILabel *label = (UILabel *)[barLabelArray objectAtIndex:index];
if(index==0){
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"position"];
animation.delegate = self;
//SOMETHING HERE
[label.layer addAnimation:animation forKey:#"position1"];
}
else if(index==1){
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"position"];
animation.delegate = self;
//SOMETHING HERE
[self.delegate startPlayVideoAtIndex:1];
[label.layer addAnimation:animation forKey:#"position2"];
}
else if(index==2){
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"position"];
animation.delegate = self;
//SOMETHING HERE
[label.layer addAnimation:animation forKey:#"position3"];
}
}
So if I wait until all animations stop, when I come back, they will start animation properly again. But sometimes I need stoping the animation in the middle of it. And then when I come back and start the animation again, all is messed up. Here is code for stoping animations:
-(void)reset{
for(UILabel *label in barLabelArray){
[label.layer removeAllAnimations];
}
}
So do you know what I am doing wrong here and how to fix it? Thank you !!
There is a way pause and resume any animations. Here is several good strings which can help you if I understand correctly
- (void) pauseLayer
{
CFTimeInterval pausedTime = [label.layer convertTime:CACurrentMediaTime() fromLayer:nil];
label.layer.speed = 0.0;
label.layer.timeOffset = pausedTime;
}
- (void) resumeLayer
{
CFTimeInterval pausedTime = [label.layer timeOffset];
label.layer.speed = 1.0;
label.layer.timeOffset = 0.0;
label.layer.beginTime = 0.0;
CFTimeInterval timeSincePause = [label.layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
label.layer.beginTime = timeSincePause;
}
I have tried so many ways but could not do it smoothly, I am a kind a newB in animations any help would be appreciated.
Code I Tried:
I have the buttons and the labels in need to add in two arrays. eventBtnsPopUpArray and eventLabelsPopUpArray. I try to add them in a loop and the animation is not smooth.
if ([eventBtnsPopUpArray count]>0)
{
CABasicAnimation* scalingAnimation;
scalingAnimation = [CABasicAnimation animationWithKeyPath:#"frame.size"];;
scalingAnimation.fromValue = [NSNumber numberWithFloat:0];
scalingAnimation.toValue = [NSNumber numberWithFloat:1024];
scalingAnimation.duration = 5.0;
scalingAnimation.cumulative = YES;
scalingAnimation.removedOnCompletion = NO;
scalingAnimation.fillMode = kCAFillModeForwards;
[calendarEventView.layer addAnimation:scalingAnimation forKey:#"rotationAnimation"];
for (int k=0; k<[eventBtnsPopUpArray count]; k++)
{
UIButton *btn = [eventBtnsPopUpArray objectAtIndex:0];
UILabel *lbl = [eventLabelsPopUpArray objectAtIndex:0];
[UIView animateWithDuration:2
delay:0
options: UIViewAnimationCurveEaseOut
animations:^{
[self addSubview:btn];
[self addSubview:lbl];
}
completion:^(BOOL finished){
[self pauseLayer:calendarEventView.layer];
[self resumeLayer:calendarEventView.layer];
}
];
}
if (calendarEventView.frame.size.width < 1024) {
[UIView beginAnimations:#"DrawLineTillEnd" context:nil];
[UIView setAnimationDuration:1.0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
calendarEventView.frame = CGRectMake(0, 65, 1024, 7);
[UIView commitAnimations];
}
}
//Pause and resume layer functions
-(void)pauseLayer:(CALayer*)layer
{
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
layer.speed = 0.0;
layer.timeOffset = pausedTime;
}
-(void)resumeLayer:(CALayer*)layer
{
CFTimeInterval pausedTime = [layer timeOffset];
layer.speed = 1.0;
layer.timeOffset = 0.0;
layer.beginTime = 0.0;
CFTimeInterval timeSincePause =
[layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
layer.beginTime = timeSincePause;
}
I don't think you need to use core-animation, just use an NSTimer and adjust the frame (width) of the UIView using a changing variable... A simple conditional statement (if-statement) checking the width can stop it at a certain point and add the first desired UIButton. When clicked this button will change a BOOLEAN which will trigger the code in the NSTimer to continue line-growth until it reaches the next width defined by the next if-statement. etc.
I dont know how you can do this using coreplot or coreanimation but doing this is really simple by view animation
for example
-(void)animateLine{
UILabel *labelObj = [[UiLabel alloc]init];
//Set background image and height of label say 100 pixel
for(int incrementer = 0; incrementer<100; incrementer ++)
{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.01];
[labelObj setFrame:cgRectMake(0,100,incrementer,20)];
[uiview commitAnimation];
}
}
I have a set of nested UIView animations (2 or 3 levels deep at a given time) that I would like to be able to pause and resume. Some of these animations use -animateWithDuration:animations:completion: while others use -animateWithDuration:delay:options:animations:completion: in order to delay execution of the animation block.
I read and implemented Technical Q&A QA1673 about pausing all animations in a layer tree, but I'm encountering an issue with the animations that use a delay parameter. I can pause and resume animations just fine, but when the animation resumes, any animation block that has a delay associated with it appears to have its delay extended by the amount of time that the layer tree was paused. So for example, if one of the blocks has a delay of 1 second, and the layer tree was paused for 3 seconds, the animation delays for 4 seconds after resuming. I'm guessing this has something to do with the beginTime property? Any help would be appreciated.
// Pause and Resume methods, right from the technical Q&A
- (void)pauseAnimationsOnLayer:(CALayer *)layer
{
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
layer.speed = 0.0;
layer.timeOffset = pausedTime;
}
- (void)resumeAnimationsOnLayer:(CALayer *)layer
{
CFTimeInterval pausedTime = [layer timeOffset];
layer.speed = 1.0;
layer.timeOffset = 0.0;
layer.beginTime = 0;
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
layer.beginTime = timeSincePause;
}
// Chained animations
- (void)animateNextPopup
{
[UIView animateWithDuration:kRFPVictorySequenceStatePopupDuration
animations:^{
[_currentStateImageView setHidden:NO];
[_currentStateImageView setTransform:CGAffineTransformIdentity];
}
completion:^(BOOL finished) {
[UIView animateWithDuration:kRFPVictorySequenceStateSlideOffDuration
delay:kRFPVictorySequenceStateVoteDelay
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
if (winnerIsDem) {
[_currentStateImageView setFrame:CGRectMake(-_currentStateImageView.frame.size.width,
_currentStateImageView.frame.origin.y,
_currentStateImageView.frame.size.width,
_currentStateImageView.frame.size.height)];
}
else {
[_currentStateImageView setFrame:CGRectMake(1024,
_currentStateImageView.frame.origin.y,
_currentStateImageView.frame.size.width,
_currentStateImageView.frame.size.height)];
}
}
completion:^(BOOL finished) {
// Do some stuff
}
];
}
];
}
I found the solution to the problem! You have to reset the self.layer.beginTime value to zero in the completion block of your animations.
e.g.
[UIView animateWithDuration:element.duration
delay:element.delay
options:UIViewAnimationOptionCurveLinear
animations:^{
// Animate properties here!
}
} completion:^(BOOL finished){
// Reset BeginTime all the time
// So, in case a pause took place the delay values are valid again!
**self.layer.beginTime = 0.0f;**
}];
The rest of the pause / resume code stays exactly the same.
Best!
I suggest a different approach.
Animation blocks are easy to implement, but useful only if you do not need any control over your animation.
Otherwise, you should use a timer and create your own animation manually.
[NSTimer scheduledTimerWithTimeInterval:0.1
target:self
selector:#selector(timerFired)
userInfo:nil
repeats:YES];
- (void)timerFired
{
if (isPaused) {
// Do nothing
} else {
// Animate
}
}
- (IBAction)pauseTapped:(id)sender
{
if (isPaused) {
isPaused = NO;
} else {
isPaused = YES;
}
}
isPaused is a flag that control your animation state.