Animations during pushing view controllers to nav. controller sometimes stop working - iphone

I use this standard code many times in my app to push VCs to nav. controller.
[self.navigationController pushViewController:detailController animated:YES];
But sometimes they stop working- view controller is pushed correcty but without animation (just as i would use "animated:NO") , and i cant figure out why.
Any suggestion what to observe or try?

Whenever you use ...animated:YES/NO the Cocoa framework will determine if it can/can not do it and more often than not it just fails. Like Michael said, you might not be on the main thread or who knows what. If you look at the latest Lion API's for fullscreen animation on an NSWindow you will find various delegates for the animation failing providing details. So I wouldn't expect Apple to go back with an animator and add such functionality.
To answer your question, primarily I would use my own custom animations using Core Animations. They really are not that bad. To get you started, you can create a Category or Class Method for convenience like this:
+ (void) animateWithDuration:(NSTimeInterval)duration
animation:(void(^)())animationBlock
completion:(void(^)())completionBlock {
[NSAnimationContext runAnimationGroup:^( NSAnimationContext *context ) {
if ( duration > 0 ) [context setDuration:duration];
[context setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]];
if ( animationBlock ) animationBlock();
} completionHandler:^ {
if ( completionBlock ) completionBlock();
}];
}
You can then use it like so for several animations. Like so...
[AnimationContext animateWithDuration:myDuration animation:^{
// You can use whatever animation you want here or even nest
CABasicAnimation *fade = /* opacity animation */;
[view.layer addAnimation:fade forKey:nil];
} completion:^{
// Do some completion here.
}];
One note, you have more control over your animations this way.
Hope this answers what you are looking for.
(Huge Note, my example is for Mac OS X. On iOS the equivalent to NSAnimationContext is to wrap using CATransaction)

Related

cocos2d: animation stopped. Integrate Cocos2D and UIKit

I already integrate Cocos2D and UIKit.
I have the navigation among the views and the first time that I open the cocos view, it works.
But when I return to my main menu, the log console displays:
cocos2d: animation stopped
After that, if I try to get in to the cocos2D view again, the animation does not start.
What can I do to solve this?
I followed this tutorial but it donĀ“t help
http://www.raywenderlich.com/4817/how-to-integrate-cocos2d-and-uikit
There have been issues regarding this. There was a similar discussion in another SO Question.
Whenever I want to include UIKit elements, I tend to do it the other way round.
With the CCUIViewWrapper code at: https://github.com/splhack/CCUIViewWrapper
This maybe be different depending on the version of cocos2d you are using, but stopAnimation should be being called on CCDirectorIOS.m:viewDidDisappear and startAnimation should be being called on viewWillAppear. So I would set breakpoints there to make sure it is being called on. And if your -(void) mainLoop:(id)sender is running.
-(void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self startAnimation];
}
-(void) viewDidDisappear:(BOOL)animated
{
[self stopAnimation];
[super viewDidDisappear:animated];
}
If you want to investigate further the mainLoop calls drawScene and if it is not isPaused, then the CCScheduler will update the CCActionManager which runs all of the animations.
Hope this helps.

iPod Touch iOS 5.1.1 Not calling viewDidDisappear:animated

I've posted this question elsewhere, but as SO is such a great community I'm doing so here as well.
First up, I'm using Cocos2D 2.0-gles20 to put a multiplayer/team oriented game together.
I've been integrating GameKitHelper into the app. To date it's been working just fine on my iPhone4 and iPad2 and in the Simulator, but now when I try to use it on an iPod Touch 4th I'm getting assertions in [CCDirectorIOS startAnimation] because the app is getting a viewWillAppear when it shouldn't and no call to viewDidDisappear when it should.
The reason this matters is that these methods on the CCDirectorIOS class cause Cocos2D to start/stop animation whilst another UIKit view is in front. This is something that I've managed myself with Cocos2D-0.99 but with 2.0 it is handled nicely within the director so that each app doesn't have to handle it specifically.
The GameKitHelper class has the following methods for pushing a GKMatchmakerViewController onto the screen:
-(void) showMatchmakerWithInvite:(GKInvite*)invite
{
GKMatchmakerViewController* inviteVC = [[[GKMatchmakerViewController alloc] initWithInvite:invite] autorelease];
if (inviteVC != nil)
{
inviteVC.matchmakerDelegate = self;
[self presentViewController:inviteVC];
}
}
-(UIViewController*) getRootViewController
{
return [CCDirector sharedDirector];
}
-(void) presentViewController:(UIViewController*)vc
{
UIViewController* rootVC = [self getRootViewController];
[rootVC presentModalViewController:vc animated:YES];
}
-(void) dismissModalViewController
{
UIViewController* rootVC = [self getRootViewController];
[rootVC dismissModalViewControllerAnimated:YES];
}
When I call showMatchmakerWithInvite, on the iPhone4, etc I see a call to viewDidDisappear: on the CCDirectorIOS object which stops animation. This is fine. When the GK view is gone, I see a call to viewWillAppear which restarts the animation. Sweet.
On the iPod Touch however, running exactly the same project, the call to viewDidDisappear is not made, but a call to viewWillAppear is, before the GK view has gone.
I can't fathom why there would be a difference. All devices are running iOS 5.1.1.
It's almost as if the behaviour of UIKit is different on the iPod Touch, but I find that hard to believe. My other thought was that I was looking at a timing issue, but I put some code in to allow the app to keep running even with the problem, but the call to viewDidDisappear never happened.
I can work around this I think by managing the start/stop of animation myself, but I would have preferred not to customise the Cocos2D code.
Does anyone have any ideas?
Thanks
Well, being the impatient person I am, rather than leave it to others and work on something else, I nutted it out.
I turns out that the iPod Touch devices in question had multi player games disabled in the restrictions app. This seems to cause the GK view to not show "properly" and as a result the events like viewDidDisappear: and viewWillAppear: don't occur the way I was expecting.
So I've been able to revert all of my tweaks and instrumentation in the Cocos2D code, and simply apply a correction to the GameKitHelper class to ensure that if features such as multi-player are disabled, the player isn't able to request them.

What is the proper way to change the UINavigationController transition effect

I have seen lots of people asking on how to push/pop UINavigationControllers using other animations besides the default one, like flip or curl.
The problem is that either the question/answer was relative old, which means the have some things like [UIView beginAnimations:] (example here) or they use two very different approaches.
The first is to use UIView's transitionFromView:toView:duration:options:completion: selector before pushing the controller (with the animation flag set to NO), like the following:
UIViewController *ctrl = [[UIViewController alloc] init];
[UIView transitionFromView:self.view
toView:ctrl.view
duration:1
options:UIViewAnimationOptionTransitionFlipFromTop
completion:nil];
[self.navigationController pushViewController:ctrl animated:NO];
Another one is to use CoreAnimation explicitly with a CATransaction like the following:
// remember you will have to have the QuartzCore framework added to your project for this approach and also add <QuartzCore/QuartzCore.h> to the class this code is used
CATransition* transition = [CATransition animation];
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
transition.duration = 1.0f;
transition.type = #"flip";
transition.subtype = #"fromTop";
[self.navigationController.view.layer removeAllAnimations];
[self.navigationController.view.layer addAnimation:transition forKey:kCATransition];
UIViewController *ctrl = [[UIViewController alloc] init];
[self.navigationController pushViewController:ctrl animated:NO];
There are pros and cons for both approaches.
The first approach gives me a much cleaner code but restricts me from using animations like "suckEffect", "cube" and others.
The second approach feels wrong just by looking at it. It starts by using undocumented transitions types (i.e. not present in the Common transition types documentation from CATransition Class Reference) which might get your app rejected from App Store (I mean might as I could not found any reference of apps being rejected because it was using this transactions, which I would also appreciate any clarification on this matter), but it gives you much more flexibility on your animations, as I can use other animation types such as "cameraIris", "rippleEffect" and so on.
Regarding all that, do I really need to appeal for QuartzCore and CoreAnimation whenever I need a fancier UINavigationController transition? Is there any other way to accomplish the same effect using only UIKit?
If not, will the use of string values like "flip" and "cube" instead of the pre-defined constants (kCATransitionFade, kCATransitionMoveIn, etc...) be an issue regarding my app approval in the App Store?
Also, are there other pros and cons regarding both approaches that could help me deciding whether to choose each one of them?
With regards to the AppStore approval, I don't think its a deal-breaker based on what animation libraries you use. You can use which ever you feel is convenient for you, and can use them together as well. From a personal standpoint, I would say the CoreAnimation & QuartzCore are pretty awesome when you are trying to add animation to a particular event. Its great because of the level of detail you can add to individual components.
But those are not your only options. You should have a look at COCOS2D libraries for animation. They are really awesome and extremely simple to use. For example if using CoreAnimation takes you 30 lines of code, you can use COCOS2D and set it up with 3-5 lines of code. Also, you can integrate Physics with each component when you use the COCOS2D framework (chipmunk).

What/How to triggers the close-iris animation of UIImagePickerController?

I'm using a custom overlay view and showsCameraControls = NO. When I'm done I dismissModalViewControllerAnimated:YES. What appears to happen is that the iris appears fully closed (ie. no closing animation - just poof and it's closed) and then immediately slides down off the screen.
As a test I manually called viewWillDisappear on the UIImagePickerController and that makes the closed iris appear, but again no smooth animation.
I also tried wrapping the dismiss in a long animation transaction and that just made the re-appearence of the underlying navigation toolbar slow down. The iris behaved just as above.
I don't want to have to make my own iris animation - that would be uncool!
PS: Using sdk 4.0
To partially answer my own question, the best I have been able to come up with so far is:
- (void)imagePickerController:(UIImagePickerController*)picker
didFinishPickingMediaWithInfo:(NSDictionary*)info
{
[picker viewWillDisappear:YES];
[self performSelector:#selector(processPickerImage:)
withObject:[[info objectForKey:UIImagePickerControllerOriginalImage] retain]
afterDelay:0.1];
}
-(void) processPickerImage:(UIImage *)uiImage
{
// do stuff
[self dismissModalViewControllerAnimated:YES];
// dismiss your custom overlay etc.
[uiImage release];
}
It doesn't actually animate the iris, but at least it is onscreen immediately so the user recognises that the photo taking is done. I'm also not super happy that viewWillDisappear gets called twice on the UIImagePickerController - I'm not sure it's guaranteed to be safe.
Also the status bar appears over the iris which is annoying.
I'm hoping someone else has a better solution?

iPhone CATransition adds a fade to the start and end of any animation?

So I am just beginning recently developing some simple apps for the iphone. I will say that I am fairly sure I don't have a strong understanding of programming for multiple views yet, but I am trying to learn as I go.
I have a program that started as a plain window based application so i could hand write everything in hopes of learning more about what i am doing. I have a single view controller that acts to load and release views as requested from each of the other view controllers. No elements persist from one view to the other.
I have that working fine currently, but I wanted to add animations to the view changing. A simple push animation was my goal. One view pushes out as the new view pushes in.
Looking into CATransitions and trying that, I have a working version (currently for pushing top/bottom)
[thisView.view removeFromSuperview];
[thisView release];
thisView = [[MenuViewController alloc] initWithNibName:#"MenuView" bundle:nil];
[self.view addSubview:thisView.view];
CATransition *animation = [CATransition animation];
[animation setDuration:6.3];
[animation setType:kCATransitionPush];
[animation setSubtype:kCATransitionFromTop];
[animation setRemovedOnCompletion:YES];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
[[self.view layer] addAnimation:animation forKey:nil];
as far as I can tell this is pretty standard code for using CATransition and it works to do what I need, one view gets pushed up as the other view comes in. However my problem is that there seems to be a fade that happens to each view as they come in or go out respectively.
As such - in this example; as the menu pushes up from the bottom, it will very slowly fade in from white, and as the previous view leaves the screen it will slowly fade to white.
Note that the duration is set to 6 so that the fading is dramatic.
Is there a way to remove the fading here so that each view remains solid on the way in and the way out? Or have I missed the mark completely in this route that I am taking?
I appreciate any help. Apologies I have been long winded.
I have never been able to find a solution to this problem, but I can offer a reasonable workaround. What's happening is it isn't fading to white, but fading to transparent, and the window background (or whatever view is behind) is white. There are a couple ways to get around this:
Change the window background color. If both views you're fading between have the same solid background color, then this will look pretty good.
Don't render a background in each view ("MenuView," for example), but rather have a shared background view that's under those views at all times.
Note that this will not work in all circumstances -- grouped UITableViews, for example, are always completely opaque.
(As I side note, I assume that you aren't build a navigation-based application, in which case all the animation should be handled automatically.)
You also might want to consider the looking into the UIView method setAnimationTransition:forView:cache: if you haven't already as another way to transition between views (although it cannot do a sliding animation, if you are set on that).
I solved this by enclosing the view to which I have applied the effect into a superview and by setting the superview property "clip subviews". now the fade is "clipped" by the superview.
I was able to get the views to transition without fading at the beginning and end by using UIView animation. NOTE: In the code below, I have a UINavigationController and a UITabBarController inside a main UIView. The main UIVIew (containerView) is what I added as a subView to the Application window. The other two are subviews of the containerView.
UITabBarController *tabBarController = [(AppDelegate_iPhone *)[[UIApplication sharedApplication] delegate] tabBarController];
UIView *containerView = [(AppDelegate_iPhone *)[[UIApplication sharedApplication] delegate] containerView];
UINavigationController *accountsNavigationController = [(AppDelegate_iPhone *)[[UIApplication sharedApplication] delegate] accountsNavigationController];
CGRect accountsNavigationControllerEndFrame = containerView.frame;
CGRect tabBarControllerEndFrame = CGRectMake(containerView.frame.size.width, containerView.frame.origin.y, containerView.frame.size.width, containerView.frame.size.height);
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.4];
tabBarController.view.frame = tabBarControllerEndFrame;
accountsNavigationController.view.frame = accountsNavigationControllerEndFrame;
[UIView commitAnimations];