I want to flip my new ModalView with very high performance, but the new View has a lot of subviews so the performance of the Flip-Effect is very bad. Actually i do it with:
[controller setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
[self presentModalViewController:backSideController animated:YES];
I also tried it with
CATransition *transition = [CATransition animation];
transition.duration = 0.75;
[transition setType: #"flip"];
[transition setSubtype:#"fromRight"];
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[transition setFillMode:#"extended"];
[[self.view layer] addAnimation:transition forKey:nil];
[self.view addSubview: backSideController.view];
[CATransaction commit];
With Core-Animation it works a little bit faster ... ware there further ways to opimize this task? e.g. Adding view when animation stops and just flipping a screenshot until animation stops?
Try accessing backsideController.view before you begin the animations. This will cause backsideController's loadView and viewDidLoad to be called. I'm guessing that this is your performance hit -- that all that loading & allocating is causing the animation to stutter.
You don't need anything fancy, you can do something like:
if (backsideController.view == nil)
NSLog(#"Where's my view?!");
before your other code, above.
I don't believe that having many-many subviews causes performance problems on the flip; I'm pretty sure (without looking at your code or checking in instruments, which you should do!) that the problem is the time it takes to load and allocate the view components.
Also, I'd stick with presentModalViewController, if it does what you want. Having all that extra code in your 2nd example -- unless it's needed for functionality -- is just maintenance headache.
Related
The code below works fine in iOS 4 and 5 but crashes in iOS 6 with EXC_BAD_ACCESS. I'd appreciate any help in troubleshooting it. This code is being called in a UITableViewController that handles my app's search logic:
CATransition *transition = [CATransition animation];
transition.duration = 0.3f;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
transition.type = kCATransitionFade;
[self.navigationController.view.layer addAnimation:transition forKey:nil];
[self.navigationController popViewControllerAnimated:NO];
The way I add the tableView is similar and doesn't crash when called:
SearchTVC *searchTable = [[SearchTVC alloc] init];
searchTable.detailViewController = self.detailViewController;
CATransition *transition = [CATransition animation];
transition.duration = 0.3f;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
transition.type = kCATransitionFade;
[self.navigationController.view.layer addAnimation:transition forKey:nil];
[self.navigationController pushViewController:searchTable animated:NO];
What could be the problem?
*EDIT
Interestingly the crash doesn't occur if I use [self.navigationController popViewControllerAnimated:YES]; (YES rather than NO). But of course this defeats the purpose of using a custom pop animation.
Check whether you have a line like the following somewhere in your view controller code:
self.navigationController.delegate=self;
If so, then you must set it back
self.navigationController.delegate=nil;
before you say
[self.navigationController popViewControllerAnimated:YES];
Otherwise, popViewControllerAnimated will first deallocate the delegate and then try to call it - resulting in a crash.
I know my question was vague, but I didn't have much else to go off of. I knew the line [self.navigationController popViewControllerAnimated:NO]; was the problem but I couldn't figure out why. Then I came across this question and the first answer suggested I make my search table an instance variable rather than creating a new one every time I want to present it, and that actually worked. It must be a memory issue that I can't wrap my head around.
tl;dr :
Make sure the UIViewController that's being pushed and popped is an instance variable.
Though super late to party... Hope this might help someone in future.
I opened a very old code...
Enabling ARC mode and then resolving all the compiler warnings/error fixed it automatically.
I'm currently performing a curl up animation by doing the following:
CATransition *animation = [CATransition animation];
animation.type = #"pageCurl";
animation.subtype = kCATransitionFromTop;
animation.fillMode = kCAFillModeForwards;
animation.duration = 1;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
[[self.view.window layer] addAnimation:animation forKey:nil];
This animation will simply perform a page curl animation but in the end you are left looking at the same view that you started out with. No REAL transition ever occurred.
Now using animation blocks I know you can do something to the effect of:
[UIView transitionFromView:self.view
toView:aNewView // a view to transition to
duration:1
options:UIViewAnimationTransitionCurlUp|UIViewAnimationOptionCurveEaseIn
completion:NULL];
However, using animation blocks you are transitioning to a new view, aNewView, which is different from the CATransition animation above which reuses the same view (no real transition ever occurs). The problem with the animation block is that you have to actually create the new view to transition to which is cumbersome in my case because the view is rather complicated and I'd rather not create a UIView subclass.
Is there a way to perform the above CATransition animation using animation blocks while getting around the difficulties of having to rebuild a view or create a custom subclass?
Ok - so I figured it out for anyone who is interested. It's actually super simple. You can simply use the method: transitionWithView:duration:options:animations:completion:
For example:
[UIView transitionWithView:self.view
duration:1
options:UIViewAnimationOptionTransitionCurlUp|UIViewAnimationCurveEaseIn
animations:^{ // do anything you want here }
completion:NULL];
That's it. This will show a transition animation back to the same view. You can make any changes you want to the new view (maybe display some new text, whatever...) in the animation block.
I hope this helps someone out down the line...
I am using the following codes to switch controller in my Three20 App
TTURLAction * urlAction = [TTURLAction actionWithURLPath:url];
[urlAction applyAnimated:YES];
CATransition * transition = [CATransition animation];
transition.duration = 0.4f;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionReveal;
transition.subtype = kCATransitionFromRight;
[self.navigationController.view.layer addAnimation:transition forKey:nil];
[[TTNavigator navigator] openURLAction:urlAction];
But the transition is strange and never as smooth as the default Three20 transition, e.g. Move from TTTableViewController to TTViewController
Any one can provide a better codes for a smoother transition?
Is it possible to transit only the content between NavigationController and TabBar? (I mean keep the button in existing NavigationController un-touched)
Thanks.
You are in fact animating twice. First you tell three20 to apply animation by [urlAction applyAnimated:YES]; and then you are attaching your own animation.
Remove applyAnimated: and it works just fine. Tested with Three20 1.0.11 on iOS5 Simulator and device.
It might be clever to use [TTNavigator navigator].topController instead of self.navigationController to get the controller which will present the url. This might be an different one under some circumstances.
I'm trying to add a sub view with Core-Animation using the attached code.
First time it happens as expected, but after that there's a flash of white in the place of the sub-view before it's fully pushed.
// Add the picker
viewToPush.frame = CGRectMake(0,185,320, 258);
CATransition *animation = [CATransition animation];
[animation setType:kCATransitionMoveIn];
[animation setSubtype:kCATransitionFromTop];
[self.view addSubview:viewToPush];
[viewToPush.layer addAnimation:animation forKey:nil];
btw, in order to remove the subView I just use
[viewToRemove removeFromSuperview];
10x
Why do you add the animation to the viewToPush's layer, not the super view's? I suspect the layer of viewToPush is not stable as you remove the view from the super view. Do you have many views that can act as viewToPush or viewToRemove so they have to be dynamically allocated? Otherwise I would just change their hidden properties to implement such animations.
I have a data entry application that has the user enter about 6 pieces of information all on different views in a navigation controller. This works fine, but once the user gets used to the application the time it takes for the next screen to appear slows the user down.
I tried the application without the animations, but it doesn't feel quite right. Is there a way to get the animations to occur quicker? I'm primarily using a navigation controller, table views, and picker views.
There's going to be a penalty each time you load a new view, you could attempt to consolidate screens using a scroll view or a different layout.
Also, if you are loading any unnecessary graphics you may want to remove them.
You could also add each view as a subview yourself in which case you have control over the animation duration among other things. This code will do that for you, although beware as I just wrote it and did not test it (The transition style and boolean parameters can be removed as they do nothing right now).
UIViewControllerExtendedPresentModalViewController.h
#import <Foundation/Foundation.h>
typedef enum _ExtendedModalTransitionStyle
{
ExtendedModalTransitionStyleTopDown
} ExtendedModalTransitionStyle;
#interface UIViewController ( ExtendedPresentModalViewController )
- (void)presentModalViewController: (UIViewController*)modalViewController
withTransitionStyle: (ExtendedModalTransitionStyle)style
animated: (BOOL)animated;
- (void)dismissModalViewController: (UIViewController*)modalViewController
withTransitionStyle: (ExtendedModalTransitionStyle)style
animated: (BOOL)animated;
#end
UIViewControllerExtendedPresentModalViewController.m
#import "UIViewControllerExtendedPresentModalViewController.h"
#import <QuartzCore/QuartzCore.h>
#implementation UIViewController ( ExtendedPresentModalViewController )
- (void)presentModalViewController: (UIViewController*)modalViewController
withTransitionStyle: (ExtendedModalTransitionStyle)style
animated: (BOOL)animated
{
[modalViewController retain]; // we'll need this for a little while, hang on to it.
CATransition* transition = [CATransition animation];
[transition setDuration: 0.4];
[transition setTimingFunction:
[CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionLinear]];
[transition setType: kCATransitionMoveIn];
[transition setSubtype: kCATransitionFromBottom];
[[[self view] layer] addAnimation: transition
forKey: nil];
[[self view] addSubview: [modalViewController view]];
}
- (void)dismissModalViewController: (UIViewController*)modalViewController
withTransitionStyle: (ExtendedModalTransitionStyle)style
animated: (BOOL)animated
{
CATransition* transition = [CATransition animation];
[transition setDuration: 0.4];
[transition setTimingFunction:
[CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionLinear]];//kCAMediaTimingFunctionEaseInEaseOut]];
[transition setType: kCATransitionReveal];
[transition setSubtype: kCATransitionFromTop];
[[[[modalViewController view] superview] layer] addAnimation: transition
forKey: nil];
[[modalViewController view] removeFromSuperview];
[modalViewController release]; // all done, we can let this go.
}
#end
Are you reusing cells in the table view? Make sure to really reuse them, in other words do all the setup of the cell inside the if(cell==nil) case and only apply the data in the common case (applying to both reuse and newly created).
Be aware of the performance hit that transparency can have in a cell. Often it seems that you have to make things transparent but maybe you don't because UITableViewCell is aware of the problems. Turning off transparency in some objects might seem wrong but is worth a try to see if it actually works. Most of the cost of scrolling a cell is the compositing as the cell moves, not creation of the cell initially.
Another thing that can help is doing the compositing of the view that you apply to your cell in advance rather than adding all the views to the cell, then you apply just one premade view to your cell.
If you are actually animating views in the scrolling cells you may need to rethink that or at least use some simplification to make it a little less taxing on the device.
You might also consider adopting Matt Gallagher's strategy for cell handling - it stops your cellForRowAtIndexPath turning into one long, nasty set of ifs.