Animate change of rootViewController to SplitViewController? - ios

I have a project that starts off with a tableView, however when the user taps the Setup button, I want to animate the change to a splitViewController.
I can easily change the rootViewController, however the animation isn't as advertised:
UIViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"SetupViewController"];
AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[UIView transitionWithView:self.navigationController.view
duration:0.75
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
app.window.rootViewController = controller;
}
completion:nil];
Is there a way I can animate this change of rootViewController?

It is a little hackie, but try setting the root before the animation and back again, so the new ViewController gets the right size when you start the animation:
UIViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"SetupViewController"];
AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
UIViewController *currentController = app.window.rootViewController;
app.window.rootViewController = controller;
app.window.rootViewController = currentController;
[UIView transitionWithView:self.navigationController.view.window
duration:0.75
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
app.window.rootViewController = controller;
}
completion:nil];
This solution worked for me.

Related

Sometimes UIView animateWithDuration happens immediately

Randomly my app will not animate at all. My app has a sound bar that gets updated every 0.1 seconds with an animation. Usually when I start the app the animations will work all pretty and everything but then at a random point usually after I transition to another view controller (via setViewControllers) it all of a sudden stops animationg. It's not just this animation but every animation in my app excluding setViewControllers.
Here is my code where I call setViewControllers:
- (void)goToController:(GeneralViewController *)vc animate:(BOOL)animated sub:(BOOL)sub{
if(animated){
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSMutableArray *viewController = [NSMutableArray arrayWithArray:[delegate.navController viewControllers]];
if(viewController.count > 0){
viewController[0] = vc;
}else{
[viewController addObject:vc];
}
CATransition* transition = [CATransition animation];
transition.duration = 0.2;
transition.type = kCATransitionPush;
if(sub)
transition.subtype = kCATransitionFromRight;
else
transition.subtype = kCATransitionFromLeft;
[delegate.navController.view.layer addAnimation:transition forKey:kCATransition];
[delegate.navController setViewControllers:viewController animated:FALSE];
self.colorStyle = MusicPlusColorStyleLight;
}else{
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSMutableArray *viewController = [NSMutableArray arrayWithArray:[delegate.navController viewControllers]];
if(viewController.count > 0){
viewController[0] = vc;
}else{
[viewController addObject:vc];
}
[delegate.navController.view.layer removeAnimationForKey:kCATransition];
[delegate.navController setViewControllers:viewController animated:FALSE];
}
}
Here is the code I use to animate the sound bar:
[UIView animateWithDuration:0.1 delay:0.0 options:UIViewAnimationCurveLinear | UIViewAnimationOptionBeginFromCurrentState
animations:^{
meterViewColor.frame = CGRectMake(0, (meterView.frameSizeHeight - (level*meterView.frameSizeHeight)), meterView.frameSizeWidth, (level*meterView.frameSizeHeight));
}
completion:nil];
I have checked and the code is running on the main thread. The CPU was on average around 10% and the Memory was 25 MB. So I am really baffled as to why it stops working sometimes. Has anyone else experienced this?
UPDATE: Sorry to say but the answer I posted was incorrect. It still isn't working. I have removed my answer and attached it bellow:
When creating the animation I added:
[transition setDelegate:self];
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag{
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[delegate.navController.view removeTransition];
}
- (void) removeTransition {
if (!CGAffineTransformIsIdentity(self.transform)) {
self.transform = CGAffineTransformIdentity;
}
}
UPDATED: I just undeleted my answer as it seems one of the properties transitionTransform should have been just transform. So it seems the animation was happening instantly because self.transform != CGAffineTransformIdentity. Even though self was the UINavigationController view it was still the superview of the views I was trying to animate.
Turns out the animation either wasn't being removed or was being removed at the wrong time.
When creating the animation I added:
[transition setDelegate:self];
And then in the delegate method:
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag{
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[delegate.navController.view removeTransition];
}
Where removeTransition was a category method on UIView defined as:
- (void)removeTransition {
if (!CGAffineTransformIsIdentity(self.transform)) {
self.transform = CGAffineTransformIdentity;
}
}

Presenting a ViewController breaks the previous ViewController

My problem is when I present a UIViewController the presenting views are going black.
I have a UIViewController named mainViewController which is the root view of my windows.
Inside I have a MMDrawerController (just added as a subview of mainViewController's view).
The MMDrawerController contains the rest of my views.
But when I'm presenting a new UIViewController from my mainViewController, the new VC displays well, but when it dismisses it left only black screen behind.
To note the black screen appears when adding (I can see it directly). Not when dismissing.
For testing purpose I did this code :
UIViewController *vc = [UIViewController new];
vc.view.backgroundColor = [UIColor redColor];
[[[[UIApplication sharedApplication] keyWindow] rootViewController] presentViewController:vc animated:NO completion:^{
[vc dismissViewControllerAnimated:YES completion:nil];
}];
Which do the same black result as normal use. (normally it's a QLViewController...)
My mainViewController is set like it :
_mainViewController = [MyMainViewController new];
_window.rootViewController = _mainViewController;
[self.window addSubview:_mainViewController.view];
Souce code of MMDrawerController which is up to date in my project
I have tested the code just in MMDrawerController example project, but I can't reproduce the problem, following is what I have tried:
MMAppDelegate.m
-(BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
//...
UIViewController *testVc = [[UIViewController alloc] init];
testVc.view.backgroundColor = [UIColor greenColor];
[testVc.view addSubview:self.drawerController.view];
[self.window setRootViewController:testVc];
[self.window addSubview:testVc.view];
return YES;
}
MMExampleSideDrawerViewController.m:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.section) {
case MMDrawerSectionViewSelection:{
UIViewController *vc = [UIViewController new];
vc.view.backgroundColor = [UIColor redColor];
UIViewController *mainVC = [[UIApplication sharedApplication] keyWindow].rootViewController;
[mainVC presentViewController:vc animated:YES completion:^{
[vc dismissViewControllerAnimated:YES completion:nil];
}];
return;
//...
}
MMExampleCenterTableViewController.m:
-(void)doubleTap:(UITapGestureRecognizer*)gesture{
UIViewController *vc = [UIViewController new];
vc.view.backgroundColor = [UIColor redColor];
UIViewController *mainVC = [[UIApplication sharedApplication] keyWindow].rootViewController;
[mainVC presentViewController:vc animated:YES completion:^{
[vc dismissViewControllerAnimated:YES completion:nil];
}];
return;
[self.mm_drawerController bouncePreviewForDrawerSide:MMDrawerSideLeft completion:nil];
}
In the end, the problem was that I applied inset constraints on my mainViewController.
Behind the scene I suppose that method presentViewController:animated:completion: use frames and not AutoLayout, which break the UIView of the UIViewController that are in the mainViewController.
Thanks to #simalone, I used the same way to find the origin of the problem (use MMDrawerController example project).
I you want to test yourself the problem, I uploaded the example project with the issue so you can understand it.
There is a breakpoint on the line which is the origin of the bug.
Then just double click on the view.
Thanks again to #simalone. Cheers !

Dismissing a modalview while changing the selected index tab not functioning

I have a tabBar application with a menu that is called up via a model view controller. Then when you select an option. I want it to dismiss while changing a SelectedIndex of the tabBAr.
here are my code snippets:
FirstTabBarController:
This is what calls the "menu"
-(IBAction)pressedButton {
GWDNativeViewController *secondView = [[GWDNativeViewController alloc] initWithNibName:nil bundle:nil];
[secondView setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[self presentModalViewController:secondView animated:YES];
}
This is the code to dismiss within the GWDNativeViewController (Menu) view:
-(IBAction)dismissThisView {
//Insert code to dismiss here
[self dismissModalViewControllerAnimated:YES];
[(UITabBarController *)self.parentViewController setSelectedIndex:3];
}
The line:
[(UITabBarController *)self.parentViewController setSelectedIndex:3];
doesn't seem to be doing the trick..
Try this:
YourAppDelegate *appDelegate = (YourAppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.tabBarController.selectedIndex = 3;

Is it right to switch in between UIViewController that way?

I want to use my own controller for navigating in between uiviewcontrollers. So like that I can have custom transitions in between my views.
I did something which is working but I'm not sure if it is the right way? Could there be problems related to memory later?...I'm not sure everything is deallocated the right way.
Thanks for your help!
Here is my code:
In my AppDelegate, when it starts:
self.rootVC = [[[MenuView alloc] initWithNibName:#"MenuView" bundle:nil] autorelease];
[self.window addSubview:self.rootVC.view];
In my AppDelegate, the method for switching in between UIViewController:
-(void) changeRootController: (NSString*) ctrlName{
UIViewController *oldVC = self.curVC;
UIViewController *newVC;
if(ctrlName == #"Studio"){
newVC = [[StudioView alloc] initWithNibName:#"StudioView" bundle:nil];
}
else if(ctrlName == #"Menu"){
newVC = [[MenuView alloc] initWithNibName:#"MenuView" bundle:nil];
}
self.curVC = newVC;
[UIView transitionWithView:self.window
duration:1.0
options:UIViewAnimationOptionCurveEaseIn
animations:^{
newVC.view.transform = CGAffineTransformConcat(newVC.view.transform, CGAffineTransformMakeTranslation(-1024, 0));
[self.rootVC.view addSubview:newVC.view];
newVC.view.transform = CGAffineTransformConcat(newVC.view.transform, CGAffineTransformMakeTranslation(1024, 0));
oldVC.view.transform = CGAffineTransformConcat(oldVC.view.transform, CGAffineTransformMakeTranslation(1024, 0));
}
completion:^(BOOL finished){
if(finished){
[oldVC release];
}
}
];
}
And I switch views in my UIViewController as follow:
AppDelegate *ad = (AppDelegate*)[[UIApplication sharedApplication] delegate];
[ad changeRootController:#"Studio"];
newVC isn't released.
The block should retain the newVc so after your transitionWithView
you should call. (last line of function)
[newVC autorelease];
Thats assuming that the self.curVC property is strong OR retained

rootViewController set but comes up as incorrect orientation

My situation is very similar to this question . I have an app that is universal where iPhone is in portrait orientation and the iPad is in Landscape and I switch between all of my main screens using the appDelegate.window.rootViewController = newScreen; The iPhone app works perfectly. The iPad app will sometime throw the screen up in portrait orientation instead of landscape. Here is some sample transition code:
AppDelegate* appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
ViewController* v = nil;
if (IS_IPAD()) {
v = [[ViewController alloc] initWithNibName:#"ViewController-iPad" bundle:nil];
}else{
v = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
}
[appDelegate.window setRootViewController:(UIViewController*)v];
I also tried this from this other question :
AppDelegate* appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
ViewController* v = nil;
if (IS_IPAD()) {
v = [[ViewController alloc] initWithNibName:#"ViewController-iPad" bundle:nil];
}else{
v = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
}
[UIView
transitionWithView:appDelegate.window
duration:0.5
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^(void) {
BOOL oldState = [UIView areAnimationsEnabled];
[UIView setAnimationsEnabled:NO];
[appDelegate.window setRootViewController:(UIViewController*)v];
[UIView setAnimationsEnabled:oldState];
}
completion:nil];
But nothing has fixed it.
Also tried using [appDelegate.window makeKeyAndVisable] and [appDelegate.window makeKeyWindow] in the hopes that this would "shock" it into doing the correct orientation.
I've got it!
Here's what my transition block looks like. The key thing I did was copy the transform (the thing that does the actual rotation) from the CALayer. Note that you'll have to include the Quartz framework and #import <QuartzCore/QuartzCore.h> at the top of your file.
[UIView transitionWithView:self.window
duration:0.5
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
BOOL oldState = [UIView areAnimationsEnabled];
[UIView setAnimationsEnabled:NO];
target.view.layer.transform = window.rootViewController.view.layer.transform;
window.rootViewController = target;
[UIView setAnimationsEnabled:oldState];
} completion:nil];

Resources