block animations: set UIViewAnimationOptionCurveLinear - iphone

Sorry, this is very basic, but I can't set the AnimationOption from the default (EaseIn) to CurveLinear. This is what I tried based on what I read in other threads:
-(void)animationShadow;
{
[UIView animateWithDuration:4
options:UIViewAnimationOptionCurveLinear
animations:^{
...
If I take out the the options bit, everything works fine. If not, it crashes. I'm sure I haven't called the right commands.
Here is the entire block animation:
-(void)animationShadow;
{
[UIView animateWithDuration:4
options:UIViewAnimationOptionCurveLinear
animations:^{
//UIViewAnimationOptionCurveLinear
// animation 1
[pageShadowView setTransform:CGAffineTransformMakeScale (3, 1)];
[pageShadowView setFrame:CGRectMake(0-350, 0, CGRectGetWidth(pageShadowView.frame), CGRectGetHeight(pageShadowView.frame))];
[UIView beginAnimations:#"pageCurlRightToLeftFinished" context:nil]; // Begin animation
//[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[pageShadowView setFrame:CGRectMake(0-280, 0, CGRectGetWidth(pageShadowView.frame), CGRectGetHeight(pageShadowView.frame))];
[UIView commitAnimations];
} completion:^(BOOL finished){ ...
EDIT:
OK, I now updated this, but I still crashes if I do the second the animation. I get the warning: UIView may not respond to +animateWithDuration ...:
-(void)animationShadow;
{
[pageShadowView setTransform:CGAffineTransformMakeScale (3, 1)];
[pageShadowView setFrame:CGRectMake(0-350, 0, CGRectGetWidth(pageShadowView.frame), CGRectGetHeight(pageShadowView.frame))];
[UIView animateWithDuration:kPageCurlSpeed/4
delay:0
options:UIViewAnimationOptionCurveLinear
animations:^{
[pageShadowView setFrame:CGRectMake(0-280, 0, CGRectGetWidth(pageShadowView.frame), CGRectGetHeight(pageShadowView.frame))];
}
completion:^(BOOL finished){
[UIView animateWithDuration:kPageCurlSpeed
delay:0
options:UIViewAnimationOptionCurveLinear
animations:^{
// animation 2
[pageShadowView setTransform:CGAffineTransformMakeScale (0.1, 1)];
[pageShadowView setFrame:CGRectMake((340-pageShadowView.frame.size.width), 0, CGRectGetWidth(pageShadowView.frame), CGRectGetHeight(pageShadowView.frame))];
}
]; // this is where I get the warning!!
}];
}

Edit: animation initialization code should be placed outside of the animation block. The block specifies the final state the views should reach at the end of animation.
[pageShadowView setTransform:CGAffineTransformMakeScale(3, 1)];
[pageShadowView setFrame:CGRectMake(-350, ...)];
[UIView animateWithDuration:4 delay:0
options:UIViewAnimationOptionCurveLinear
animations:^{
[pageShadowView setFrame:CGRectMake(-280, ...)];
}
completion:NULL];
If you want to run 2 animations sequentially, the 2nd one should be put in the completion block.
[UIView animateWithDuration:4 delay:0
options:UIViewAnimationOptionCurveLinear
animations:^{ /* animation 1 */ }
completion:^(BOOL finished) {
/* animation 2 */
}];

If you find that your selected curve is being ignored, check that you are using the right set of switches.
There is one called UIViewAnimationCurveLinear (for older methods) and UIViewAnimationOptionCurveLinear (for block methods) and its easy to mix them up. there are corresponding equivalent pairs for ease in, ease out etc.
This caught me out so I thought I'd make sure the information was easily visible for others.

Related

Running an animation one after the other fails

I'm trying to animate an image to rotate left and right when selected, basically to let the user which the object they're touching.
I found some code for animating:
- (void)rotateImage:(UIImageView *)image duration:(NSTimeInterval)duration
curve:(int)curve degrees:(CGFloat)degrees delay:(CGFloat)delay
{
// Setup the animation
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelay:delay];
[UIView setAnimationDuration:duration];
[UIView setAnimationCurve:curve];
[UIView setAnimationBeginsFromCurrentState:YES];
// The transform matrix
CGAffineTransform transform =
CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(degrees));
image.transform = transform;
// Commit the changes
[UIView commitAnimations];
}
However, when I try to run two animations, only the last one ever works. Even with a proper delay, only the second animation will show:
[self rotateImage:self duration:.5
curve:UIViewAnimationCurveEaseIn degrees:60 delay:0];
[self rotateImage:self duration:.5
curve:UIViewAnimationCurveEaseIn degrees:-60 delay:5];
What can I do to create the animation so it rotates left, then rotates right?
[UIView animateWithDuration:0.2 animations:^{
// animation left
[UIView setAnimationDelay:10];
} completion:^(BOOL finished){
[UIView animateWithDuration:0.2 animations:^{
// animation right
} completion:^(BOOL finished){
// done
}];
}];
found it here
https://developer.apple.com/library/content/featuredarticles/Short_Practical_Guide_Blocks/
[UIView animateWithDuration:0.5f delay:0.0f options:UIViewAnimationOptionCurveEaseIn animations:^{
self.view.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(60));
} completion:^(BOOL finished){
[UIView animateWithDuration:0.5f delay:5.0f options:UIViewAnimationOptionCurveEaseIn
animations:^{
self.view.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(-60));
}
completion:^(BOOL finished){}];
}];
Animation blocks are definitely the way to go. This should replicate what you're trying to do, including the easing. This assumes your calling from a view controller, but if your putting this code into a UIView or UIImageView, then just replace self.view with self.
[UIView animateWithDuration:0.5f delay:0.0f options:UIViewAnimationOptionCurveEaseIn animations:^{
self.view.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(60));
} completion:^(BOOL finished){}];
[UIView animateWithDuration:0.5f delay:5.0f options:UIViewAnimationOptionCurveEaseIn animations:^{
self.view.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(-60));
} completion:^(BOOL finished){}];

How to scale UIImageView properly with UIView animateWithDuration?

I'm scaling UIImageView and then reverting it using UIView animateWithDuration with UIViewAnimationOptionAutoreverse option. The problem is the image animation is a little bit jaggy (twitching) at the end of the animation. Here's my code:
[UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionAutoreverse
animations:^{
myImage.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.9, 0.9);}
completion:^(BOOL finished){if (finished){
myImage.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.0, 1.0);}}];
I know that I'm missing something but don't know where to start :(
UPDATE1: I'm performing nested 6 animations where each next animation performs after previous one. For that I'm using block animations and performing each next animation in complete block.
UPDATE2: I have tried with UIViewAnimationOptionRepeat option but there's still some flash effect after each scale animation.
UIViewAnimationOptionAutoreverse does nothing without also using the UIViewAnimationOptionRepeat option. Your animation as written will shrink the image to 90%, then snap back to 100% in the completion block. Maybe you can follow this animation with another that scales back to 100% over a quarter second. Something like this:
[UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionCurveEaseInOut
animations:^{
myImage.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.9, 0.9);}
completion:^(BOOL finished){if (finished){
[UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionCurveEaseInOut
animations:^{
myImage.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.0, 1.0);}
completion:NULL];}}];
.h file declerd.
NSInteger imgint;
.m file in code and try.
-(void)
{
[NSTimer scheduledTimerWithTimeInterval:(0.85f)target:self selector:#selector(play_btn_animation) userInfo:nil repeats:YES];
}
-(void)play_btn_animation
{
if(imgint == 0)
{
[UIView animateWithDuration:0.8
delay:0.0
options: UIViewAnimationOptionCurveEaseIn
animations:^{
img.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.8, 0.8);
}
completion:^(BOOL finished) {
img = 1;
}];
}
else
{
[UIView animateWithDuration:0.8
delay:0.0
options: UIViewAnimationOptionCurveEaseOut
animations:^{
img.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1, 1);
}
completion:^(BOOL finished) {
imgint = 0;
}];
}
}

how to stop an already running animation

I am doing some animation using block level technique. I want to stop the animation on the basis of certain condition. How will I stop the animation from completing?
Following is my code for animation:
[UIView animateWithDuration:2.0 delay:0.0 options:UIViewAnimationOptionAllowUserInteraction
animations:^{
if([arrAns count]>0)
vwb1.center = CGPointMake(260, 40);
}
completion:^(BOOL finished){
[UIView animateWithDuration:1.5 delay:0.0 options:UIViewAnimationOptionAllowUserInteraction
animations:^{
if([arrAns count]>1)
vwb2.center = CGPointMake(260, 100);
}
completion:^(BOOL finished){
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionAllowUserInteraction
animations:^{
if([arrAns count]>2)
vwb3.center = CGPointMake(260, 160);
}
completion:^(BOOL finished){
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionAllowUserInteraction
animations:^{
if([arrAns count]>3)
vwb4.center = CGPointMake(260, 220);
}
completion:^(BOOL finished){
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionAllowUserInteraction animations:^{
if([arrAns count]>4)
vwb5.center = CGPointMake(260, 280);
} completion:nil];
}];
}];
}
];
}];
I am not having any key here so I can nnot remove it on the basis of a key. There is also a feature as removeallanimation but I am not able to use it. If someone could help me on how to use that it will also be fine.
Edit: Ok I figured out how to do it, I am doing it using following code:
[self.view.layer removeAllAnimations];
But now I have problem that my block level animation which have not yet started is still running. So if I remove the animation at second block it still executes remaining block. I need to stop that also.
Thanks
Pankaj
You should check finished variable. And start next animation (inside a block) only if previous was finished (finished == YES), not stopped.
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion
...
completion
A block object to be executed when the animation sequence
ends. This block has no return value and takes a single Boolean
argument that indicates whether or not the animations actually
finished before the completion handler was called. If the duration of
the animation is 0, this block is performed at the beginning of the
next run loop cycle.

Error: Parameter name omitted

I'm trying to have an auto reversing animation, and am getting the above error on the "completion:^(BOOL)finished{" line.
[UIView animateWithDuration:0.5
delay:0
options:UIViewAnimationOptionAutoreverse
animations:^{
[[[self dieButtons] objectAtIndex:i] setTransform:CGAffineTransformMakeTranslation(0, 200)];
}
completion:^(BOOL)finished{
}];
Note I first attempted this with the following code but the button jumped to the new location at the end of the animation.
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationRepeatAutoreverses:YES];
[button setTransform:CGAffineTransformMakeTranslation(0, 200)];
[UIView commitAnimations];
finished is the name of the BOOL parameter, and Objective-C blocks have C-style function signatures, so it has to be in the parentheses.
The block's signature is supposed to look like this:
^(BOOL finished) {
}

iPhone page curl transition animation

I'm trying to instigate a page curl transition with a UIImageView in a Window. This code is in my main init method :
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.5];
[UIView setAnimationDelay:delay];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDidStopSelector:#selector(animCompleteHandler:finished:context:)];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:splashImage cache:YES];
splashImage.frame = CGRectMake(-320, 0, 10, 10);
//[splashImage removeFromSuperview];
[UIView commitAnimations];
The image animates position and size but no curl. If I uncomment the removeFromSuperView it just vanishes instantly. Any ideas?
UPDATE:
Have changed the code so it uses Lars fantasticlly neat way of triggering an animation and including the animation and callback ...
[UIView animateWithDuration:1.5
delay:delay
options: UIViewAnimationTransitionCurlUp
animations:^{splashImage.alpha = 0;}
completion:^(BOOL finished){[splashImage removeFromSuperview];}
];
Unfortunately the page curl just doesn't happen. It does fade though.
I'm not sure if this is something to do with the syntax or the fact that the SplashImage is a UIImageView class in the UIWindow object of my main view. Maybe it needs to be in a UIView to create the transition.
Try something like:
[UIView transitionWithView:splashImage
duration:1.5
options: UIViewAnimationOptionTransitionCurlUp
animations^{
splashImage.frame = CGRectMake(-320, 0, 10, 10);
}
completion:^(BOOL finished){
[splashImage removeFromSuperview];
//animCompleteHandlerCode..
}
];
Not tested and maybe some syntax errors but give it a try!
Or maybe this is better:
[UIView animateWithDuration:1.5
delay:delay
options: UIViewAnimationOptionTransitionCurlUp
animations^{
splashImage.frame = CGRectMake(-320, 0, 10, 10);
}
completion:^(BOOL finished){
[splashImage removeFromSuperview];
//animCompleteHandlerCode..
}
];
#Larsaronen: Thanks for the examples, it was exactly what I needed! I just wanted a simple page curl while images are first displayed, so I used an alpha of 1.0 instead of 0, and set the completion callback to nil:
// set a page curl animation for the specified UIImageView control
- (void) setAnimationPageCurl:(UIImageView *)imageView {
[UIView transitionWithView:imageView
duration:1.5
options:UIViewAnimationOptionTransitionCurlDown
animations:^ { imageView.alpha = 1.0; }
completion:nil];
}