Difficulty chaining two UIView animations - objective-c

Here's what I'm trying to accomplish.
A UILabel will appear on screen at 100% alpha and move up 80pts using a UIView animation. As soon as that animation ends, I want it to continue 80pts higher while fading out to alpha 0. I want these two animations to appear as one seamless animation.
I thought maybe I could do this with a UIView animation and then put a second UIView animation in the completion block as shown below. However, there appears to be a delay before the completion block is executed which prevents the two animations from appearing seamless.
Can anyone tell me the best way to do what I'm trying to do?
Thanks!
[UIView animateWithDuration:1.2 delay:0 options:UIViewAnimationCurveLinear animations:^{
myLabel.center = endPoint;
}
completion:^(BOOL finished) {
[UIView animateWithDuration:1.2 delay:0 options:UIViewAnimationCurveLinear animations:^{
myLabel.center = endPoint2;
myLabel.alpha = 0;
}
completion:^(BOOL finished) {
NSLog(#"animations complete");
}];
}];

This should work. I see no reason why not. Just a small addition, check for animation completion in finished block. As this will take care of any errors during animation. Also if you are planning to make this UILabel tappable then you need to make it so by setting the flag UIViewAnimationOptionAllowUserInteraction.
[UIView animateWithDuration:1.2 delay:0 options:UIViewAnimationCurveLinear | UIViewAnimationOptionAllowUserInteraction animations:^{
myLabel.center = endPoint;
myLabel.alpha = 1;
}
completion:^(BOOL finished) {
if(finished){
[UIView animateWithDuration:1.2 delay:0 options:UIViewAnimationCurveLinear | UIViewAnimationOptionAllowUserInteraction animations:^{
myLabel.center = endPoint2;
myLabel.alpha = 0;
}
completion:^(BOOL finished) {
NSLog(#"animations complete");
}];
}
}];

Related

setNavigationBarHidden with options

Is there a way to adjust the duration and curve of the setNavigationBarHidden method of a UINavigationController? It appears far too quickly and does not mesh with the other animations on my app.
You could create your own hide animation as follows:
[UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
self.navigationController.navigationBar.alpha = 0;
} completion:^(BOOL finished) {
[self.navigationController setNavigationBarHidden:YES animated:NO];
}];

iOS Sliding Animation Happens Twice Unwantingly

I'm working on a page-based iPhone app using Xcode 4.4 with ARC and have been stuck on this for awhile. On a certain page, a UIImageView finger needs to slide up and point to something and then slide left off the screen. This works as expected when I run it once, but when I turn the page and go back - there is now 2 fingers sliding about 0.5 seconds out of sync with eachother.
Here's the code:
-(void)fingerSwipeUp:(UIImageView *)imageView
{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1];
[imageView setCenter:CGPointMake(213.75,355.5)];
[UIView commitAnimations];
}
-(void)fingerSwipeLeft:(UIImageView *)imageView
{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1];
[imageView setCenter:CGPointMake(-80,355.5)];
[UIView commitAnimations];
}
UIImageView *finger = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"finger.png"]];
// position finger off the screen
[finger setFrame:CGRectMake(142.5,480,152.5,243)];
[self.view addSubview:finger];
[self performSelector:#selector(fingerSwipeUp:) withObject:finger afterDelay:6];
[self performSelector:#selector(fingerSwipeLeft:) withObject:finger afterDelay:8];
Any help greatly appreciated
I'm guessing that you're creating the "finger" view in ViewDidAppear()? If that's the case, every time the page is turned (hidden) and then gone back to, you're adding another arrow (subview). What about this instead:
if (finger == nil) {
finger = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"finger.png"]];
[finger setFrame:CGRectMake(142.5,480,152.5,243)];
[self.view addSubview:finger];
}
[self performSelector:#selector(fingerSwipeUp:) withObject:finger afterDelay:6];
[self performSelector:#selector(fingerSwipeLeft:) withObject:finger afterDelay:8];
If you've got a number of animations in a sequence, you might find it easier to use the block-based UIView animation syntax:
[UIView animateWithDuration:1.0 delay:6.0 options:UIViewAnimationCurveEaseInOut animations:^{
// animation 1
} completion:^(BOOL finished) {
[UIView animateWithDuration:1.0 delay:8.0 options:UIViewAnimationCurveEaseInOut animations:^{
// animation 2
}];
}];
This will only start animation 2 after animation 1 has finished, so you don't need to worry about allowing for the duration of animation 1 when delaying animation 2.

animateWithDuration not working

I'm trying to animate a view with some buttons and controllers for my main view into the screen from the right side of the screen. The problem is it doesn't animate, it just goes directly to the finished state.
This is my code:
UIStoryboard* storyBoard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
options = [storyBoard instantiateViewControllerWithIdentifier:#"OptionsView"];
options.delegate = self;
[self.view addSubview:options.view];
options.view.center = CGPointMake(floor(total_width+options.view.frame.size.width/2)+10, floor(total_height/2));
[UIView animateWithDuration:0.5
delay:0.0
options: UIViewAnimationOptionCurveEaseOut
animations:^{
options.view.center = CGPointMake(floor(total_width-options.view.frame.size.width/2)+10, floor(total_height/2));
}
completion:^(BOOL finished){
NSLog(#"Done!");
}];
EDIT
To make things more strange, if I put this animation inside the completion block of another animation then this one works, but not the new one.
UIButton* boton = (UIButton*) sender;
[UIView animateWithDuration:5.0
delay:0.0
options: UIViewAnimationOptionCurveLinear
animations:^{
boton.alpha = 0.0;
//Jumps directly to 0, animation doesn't work
}
completion:^(BOOL finished){
[UIView animateWithDuration:0.5
delay:0.0
options: UIViewAnimationOptionCurveEaseInOut
animations:^{
options.view.center = CGPointMake(floor(total_width-options.view.frame.size.width/2)+10, floor(total_height/2));
//It works now, but it doesn't take 5 seconds to start, it starts right away
}
completion:^(BOOL finished){
NSLog(#"Done!");
}];
}];
The line before the animateWithDuration:... call directly assigns the center to the same value that you're animating to. Either remove that or assign the initial center value there. An animation that has the same start and end values obviously has no effect.

Triggering a method after a delay without abusing [UIView animateWithDuration]?

I have a UIViewController that should control 2 UIImageViews to fade in.
I managed to animate them using the UIView animateWithDuration method, like this:
[UIView animateWithDuration:1.5
animations:^{
[mFrontpageTitle setAlpha:0];
[mFrontpageTitle setAlpha:1];
}
completion:^(BOOL finished){
[self AnimatePause];
}];
and
-(void)AnimatePause {
[UIView animateWithDuration:5.0
animations:^{
[mFrontpageTitle setAlpha:0.99];
[mFrontpageTitle setAlpha:1];
}
completion:^(BOOL finished){
[self AnimateAuthor];
}];
which fires the next animation. Now, creating a transition from .99 to 1.0 is not very clean.
Is there a better way to trigger a block or sending a message by just defining a duration?
thanks
Zuppa
NSTimeInterval delay = 1.5; //in seconds
[self performSelector:#selector(myMethod) withObject:nil afterDelay:delay];

I want to flash an UIImageview on the iPad, how do I do that?

I want to let a UIImageView flash several times.
Currently I don't know how to do that.
Actual code:
-(void)arrowsAnimate{
[UIView animateWithDuration:1.0 animations:^{
arrow1.alpha = 1.0;
arrow2.alpha = 1.0;
arrow3.alpha = 1.0;
NSLog(#"alpha 1");
} completion:^(BOOL finished){
[self arrowsAnimate2];
}];
}
-(void)arrowsAnimate2{
[UIView animateWithDuration:1.0 animations:^{
arrow1.alpha = 0.0;
arrow2.alpha = 0.0;
arrow3.alpha = 0.0;
NSLog(#"alpha 0");
} completion:^(BOOL finished){;}];
}
later on I call it like this:
for (int i = 0;i < 10; i++){
[self arrowsAnimate]; }
This gives me 10x alpha 1, and then 10x alpha 0. In the middle we see only one animation.
Any suggestions?
Thanks.
There is a simpler way to achieve a flashing animation using only 1 animation block:
aview.alpha = 1.0f;
[UIView animateWithDuration:0.5f
delay:0.0f
options:UIViewAnimationOptionAutoreverse
animations:^ {
[UIView setAnimationRepeatCount:10.0f/2.0f];
aview.alpha = 0.0f;
} completion:^(BOOL finished) {
[aview removeFromSuperview];
}];
The trick is to use [UIView setAnimationRepeatCount:NTIMES/2]; *_inside_* your animation block.
No need for extra functions or extra loops.
Use
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion
and pass the UIViewAnimationOptionRepeat and probably UIViewAnimationOptionAutoreverse in your options. You shouldn't need to provide a completion block and only perform the first animation.
Edit: here is some sample code for an image that fades in and out indefinitely.
[UIView animateWithDuration:1.0
delay:0.0
options:(UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse)
animations:^{
self.myImageView.alpha = 1.0;
}
completion:NULL];
Edit 2: I see you actually need to flash it 10 times only. I wasn't able to do that with blocks actually. When the completion block executed, the animation seemed to complete instantly the remaining 9 times. I was however able to do this with just the old-style animations quite easily.
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0];
[UIView setAnimationRepeatCount:10.0];
[UIView setAnimationRepeatAutoreverses:YES];
self.myImageView.alpha = 1.0;
[UIView commitAnimations];
Edit 3: I found a way to do this with blocks.
- (void)animate
{
if (self.animationCount < 10)
{
[UIView animateWithDuration:1.0
animations:^{
self.myImageView.alpha = 1.0;
}
completion:^(BOOL finished){
[self animateBack];
}];
}
}
- (void)animateBack
{
[UIView animateWithDuration:1.0
animations:^{
self.myImageView.alpha = 0.0;
}
completion:^(BOOL finished){
self.animationCount++;
[self animate];
}];
}
Above blinking may not work when your app go background and foreground at time of blinking.
Instead of these you can take a transparent image and your actual image and animate your ImageView
UIImageView *imageview=[UIImageView new];
imageview.animationDuration=1;
imageview.animationImages = your array of images;
[imageview startAnimating];
You need to wait for an animation to complete before launching a new one. You could chain your completion block in animate2 to go back to animate, and stop based on a counter property, implementing your loop in the animate/completion blocks instead of a separate loop.