How to continue UIImageView animation after didEnterBackground? - ios

I have a simple UIImageView (myimageview) loaded with an NSArray(animationArray) of images for animation (in my ViewController.m):
[self.myimageview setAnimationImages:self.animationArray];
[self.myimageview setAnimationDuration:[self durationTime]];
[self.myimageview setAnimationRepeatCount: 1];
[self.myimageview startAnimating];
I know where to use stopAnimating, etc.. However I have weird problem. When the screen locks then nothing happens to my animation. Anything works like a charm. It continue after I unlock the screen.
However when my app goes in to Background mode then the whole animation stops (my animations are 2-3 minutes long, thus it is not acceptable). I've searched a little and found this topic:
How to pause a UIImageView animation
Where it says to use this code:
UIView *viewBeingAnimated = //your view that is being animated
viewBeingAnimated.frame = [[viewBeingAnimated.layer presentationLayer] frame];
[viewBeingAnimated.layer removeAllAnimations];
//when user unpauses, create new animation from current position.
Now I'm trying to implement this to my code in AppDelegate.m
// in -(void)applicationDidEnterBackground:
self.viewController.myimageview.frame = [[self.myimageview.frenchPress.layer presentationLayer] frame];
However i got this issue within XCode (for the line above) and I can't further continue:
AppDelegate.m:40:47: Receiver type 'CALayer' for instance message is a forward declaration
I'm saving the time if I exit into the background to the value: self.currentDate (just for sidenote, in case we need it).
How can i pause and play the animation without interruptions?

In order to get access to all the messages and properties of CALayer, you have to include its corresponding framework header:
#import <QuartzCore/QuartzCore.h>
This will hopefully eliminate the warning.

Related

UIButton state transition animation not working for setEnabled or setHighlighted

Update
The animation is working for setEnabled=NO.
The animation for setEnabled=YES is being triggered when UIScrollView is scrolling, the UIButton is inside the scrollview and the animation for setEnabled=NO is being triggered when UIScrollView is done scrolling.
So, I think the reason why animation for setEnabled=YES is not working is because the view is moving. I am not sure but this seems to be the only logical explanation from what I have found so far. I did a test with dispatch_after() and the animation worked for setEnabled too, in other words the animation is working if it is being triggered when the view is not moving.
What I need to do ?
I have two different background images for UIButton one for UIControlStateNormal and another for UIControlStateDisabled.
I want a effect where UIButton slowly transitions over from one state to another
What have I been doing ?
BOOL enableDisable = YES;
[UIView transitionWithView:((UIButton*)object)
duration:3.3
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{ [((UIButton*)object) setEnabled:enableDisable]; }
completion:nil];
The Problem
UIButton transforms to setEnabled=NO state over the duration but no matter what I put in the options setEnabled happens almost instantly.
is there something I am missing ?
Thanks in advance for your time and response.
Unfortunately, enable or disabled state for UIView aren't part of animatable properties in apple docs. The animatable properties are:
frame, center, bounds, transform, alpha, backgroundColor, contentStretch
Reference here: UIView animation
However if you want to create custom property for animation, you can have a look at this post which describes a way to achieve it. Create a custom animatable property
I can confirm that your code works as expected both for the transition
enabled: NO -> YES
and for the transition
enabled: YES -> NO
So, my guess is that something else is happening in your app that somehow interferes with the transition. Try defining a completion block like:
...
completion:^(BOOL finished) {
NSLog(#"FINISHED? %#", finished?#"YES":#"NO");
} ];
and add a trace log before the transitionWith call or inside the animation block to check how long the transition runs from start to completion.
My guess is that while the button is transitioning something else is happening that changes its state and as a secondary effect breaks the transition. I fear that without seeing more code, it will not be possible to help you further...

Setting the previous image right before calling transitionWithView

I have a placeholder UIImageView (loaded from a .xib) which I want to load with a picture of the back of a card and then flip to the front image.
[cardView setImage:backCardImage];
[UIView transitionWithView:cardView
duration:1
options:UIViewAnimationOptionTransitionFlipFromLeft
animations:^{
[cardView setImage:frontCardImage];
}
completion:NULL];
The problem is that the initial image it starts with is not backCardImage, instead, it uses the no image (i.e. blank image) from my .xib file. If I had the backCardImage loaded in the .xib and only call transitionWithView, I believe it would work properly, but I would really like to have the two calls (setImage, and transitionWithView) in the same method. Is there any way to do this? Do I need to call something between the two?
I tried using UIViewAnimationOptionBeginFromCurrentState, but that doesn't work either.
The cardView won't draw, even if you put in setNeedsDisplay, until the next drawing cycle, so you need to set that image in another method first, or move the animation to another method, and call it with performSelector:withObject:afterDelay:. Even a delay of 0 will work. I don't think the animation looks very good though, because you only see the back image for an instant before the flip (a delay of .1 or .2 seconds looks better I think). Why not set the back image earlier? What's the purpose of a placeholder image in this context?

UIImageView Animation decreasing Width

I am developing an application which needs to decrease the width of imageview to 0 from 320 in a 1hour time. for this i am using following code
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:3600];
newRect.size.width = 0;
imgView.frame = newRect;
[UIView commitAnimations];
it is works fine if we stay in same view controller,after animation starts if the user navigate to some other viewcontoller, How to handle the animation.
Along with this i have one more issue- during the animation the image in imageview is looks like shrink as throughout the animation i am using same image ,So i want to change the image in imageView during the animation How can i achieve this.
Is there any other way to do this apart form the animation.
Any Help is Appreciated.
The life cycle of the controllers and views will not allow you to do this so simply. The objects you are using can and will be deallocated by the system if they are not currently needed anymore, so the animation you started is essentially discarded with it.
You will have to store the progress of your animation somewhere, e. g. in a file or a CoreData database to have it persistent across the instantiations of that view. Depending on the exact situation, it might be sufficient to store the start time of the animation once it begins. Then, in viewWillAppear you could load it and calculate how much progress into that one hour has been made and start a new animation from that point. To the user it would appear as if the animation had proceeded in the background.

In iOS, How can I delay auto-rotation during a custom animation (segue)

In iOS (version 5 is fine), I have a custom animation to flip and zoom an image transitioning from one UIViewController to another using:
TCFlipZoomSubviewSegue segue=[[TCFlipZoomSubviewSegue alloc] initWithIdentifier:#"SegueToMenuTable" source:self.iViewController destination:self.mViewController];
[segue perform];
and in the perform method I have:
[UIView animateWithDuration:3.75f
delay:0.0f
options:UIViewAnimationOptionAllowAnimatedContent
animations:^{
self.subviewTransformView.layer.transform=transform;
} completion:^(BOOL finished) {
[destination.parentViewController.view bringSubviewToFront:destination.view];
}
It all works fine, but all sorts of problems occur (layout is messed up) if I rotate the device during the animation. What I want is for the animation to complete before the orientation event occurs - which is the standard behaviour in iPhones - eg try rotating the MAIL app immediately after clicking INBOX - it completes the slide transition then rotates. Same with the Stocks app etc. And that's what happens if I use a standard Push animation etc. But I have my own animation to do.
So how do they do that?
How do I prevent (ie delay, or block) the orientation change until my animation finishes? I can easily stop the change by saying NO in shouldAutorotateToInterfaceOrientation: when I'm animating but then i need it to do the orientation after. I could call attemptRotationToDeviceOrientation but surely there must be a better way - The segue itself should be able to complete without being interrupted.
I think the way you mentioned is probably the way you have to do it -- that is, return NO to shouldAutorotateToInterfaceOrientation:, and then call attemptRotationToDeviceOrientation when your animation is done. You would probably need some sort of flag that is set if the user tries to rotate while the animation is in progress, so you would know whether you should call attemptRotationToDeviceOrientation when the animation finishes.

Xcode: Move image (Quartzcore) + running 2 IBActions, one immediately after the other in 1 click with time respected

I have a question regarding Xcode.
I found a tutorial on the net that allowed me to move an image around the screen.
Could you please explain how I can make my button move to the left and back to right with one click (I can't find this anywhere...), and immediately after that run another IBAction that allows me to switch to another subview? (I already have this code naturally...). I tried to add both IBActions in 1 centralized one, but it didn't seem to work :-( It opens in this case immediately the subview without showing me the animation.
What I tried:
The code obtained until now:
-(IBAction) aMove: (id) sender{
if (bMove == NO) {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
btnTarget.transform = CGAffineTransformMakeTranslation(-30,0);
[UIView commitAnimations];
bMove = YES;
}else{
btnTarget.transform = CGAffineTransformIdentity;
bMove = NO;
}
}
-(IBAction) aAnimateActivate: (id) sender {
[self aMove:nil];
[self targetOpenView:nil]; //Opens the subview
}
I appreciate your help! Thanks!
concatenate works to combine animations and I just put two blocks of animations (two of the one shown below) after each other... :
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:.3];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
CGAffineTransform transform = CGAffineTransformConcat(CGAffineTransformMakeScale(1, 1),CGAffineTransformMakeTranslation(10, -50));
btnGuide.transform = transform;
[btnGuide setAlpha:0.0];
[UIView commitAnimations];
Basically implementing this code did the trick... Easy!
However... I needed some additional pieces of code for the further implementation such as:
[self performSelector:#selector(aGuide) withObject:self afterDelay:0.0];
(don't mind the selector name)
and:
[NSTimer scheduledTimerWithTimeInterval:.5 target:self selector:#selector(targetOpenView:) userInfo:nil repeats:NO];
Without looking at all of your program flow nor doing any actual testing (and I find when using Core Animation that the only way to be sure it works right is to code it and see if it does) the problem with the subview opening right away occurs because right after you invoke your "aMove" method to set up the first animation the thread continues with the next line of code, i.e., the [self] targetOpenView:nil statement, which immediately opens the subview and thus doesn't allow the first animation sequence to be shown. There is no pause to wait for the first animation to be completed. The animation, once commited, runs on its own thread while your code continues to run on the current thread (probably the application's main thread). That might not seem to be the most sensible way but you have to think of the code you write as the process to set up an animation that, once committed, is a separate entity that is free to run on its own (beside your code). The advantage to Apple's implementation is that you can set up a whole bunch of different animations which occur at the same time. One of Core Animation's design goals is to take away the need for the programmer to be handling all the starting and stopping of various animations and instead let the animation coordination be done using various methods of delay and duration or providing the means for one animations events to be observed (and acted upon) by other animations.
In order to do the animation(s) the way you want you will need use a method which only allows the second animation to begin once the first is over. One way (assuming that the subview change would be set up as an animation itself) is to use a completion: handler, an animation block that only begins upon completion of the first animation. Another way is to let the two animations "start together" but include a delay: parameter in the second animation that is equal to the length of the first animation. If the subview change is not done with an animation but is just done with code in the main thread then you need to set up a an animation delegate that is called when certain events occur in your animation, one of which is it's completion. Parameter(s) are passed to your delegate to tell you what is occurring and to which animation.
All of this is discussed, with examples, in the Animations section of the View Programming Guide to iOS (about 10 pages that will probably show you almost exactly how to do what you want):
http://developer.apple.com/library/ios/#documentation/WindowsViews/Conceptual/ViewPG_iPhoneOS/AnimatingViews/AnimatingViews.html#//apple_ref/doc/uid/TP40009503-CH6
Also, in order to set up the first animation to move the button somewhere and back again you might want to read the subtopic in that same section of the guide mentioned above: Implementing Animations That Reverse Themselves. I think it would be the cleanest way to do what you want.
(FYI, I'm better with the MacOS side of Core Animation than the iOS side but the "why did this happen immediately?" problem you have is a common pitfall when getting up to speed with how it works. Hope this explanation helps.)

Resources