How to chain modal views from a controller launched from UITabBarController - iphone

How would I go about chaining several modal controllers from a UITabBarController's view? The View Programming Guide from Apple says this is feasible but when I attempt such a task, I get the error,
"*Assertion failure in -[UIWindowController transition:fromViewController:toViewController:target:didEndSelector:], /SourceCache/UIKit_Sim/UIKit-1447.6.4/UIWindowController.m:186
The Class hierarchy is something like this:
UITabBarController -> 1 child is a UIViewController inherited class named, Tab1Controller.
Tab1Controller -> orchestrates each of the 2 controllers that need to be presented modally.
Launches 1 modal UIViewController and when this finishes up (get called via a callback), dismisses it and then initiates another modal UIViewController.
It's as if there's not enough time between the two modal controllers ending and starting.
Is there any sample code that shows how to have one modal controller after another can be chained?

See my answer to this SO question:
Correct way of showing consecutive modalViews

It's as if there's not enough time between the two modal controllers ending and starting.
I think you've hit the nail on the head there. You cannot present a new modal view controller until the previous one has finished disappearing and the viewDidAppear: method is called on the view controller that had been being covered by the old modal view.
Another option would be to present the second modal view on top of the first, e.g.
[firstModalViewController presentModalViewController:secondModalViewController animated:YES]
You can then call [firstModalViewController dismissModalViewControllerAnimated:YES] to dismiss the second (returning to the first), or [self dismissModalViewControllerAnimated:YES] to dismiss both at once.

// present modal view inside another presented modal view
FirstViewController *firstVC = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController: firstVC];
// Note: you can use your viewcontroller instead self.window.rootViewController
[self.window.rootViewController presentViewController:navController animated:YES completion:^{
//code...
SecondViewController *secondVC = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
[navController presentViewController: secondVC animated:YES completion:nil];
}
}];

Related

UIViewController Transition from right to left

I am opening second view controller on button click from fist viewController,but its animating from bottom.I want to open it in right to left.
You may be presenting the second view controller on first view button tap.
The view transition from right to left will work when you do pushing a second view.
For enable pushing the second view, at first your first view should be inside navigation controller.
If your first view is already inside a navigation controller then do the following for pushing second view:
Case 1: If your are using storyboard and First view is already embedded in Navigation controller
set storyboardID for the second view controller in storyboard (Eg. here storyboardID is same as the class name)
Do this code on your button tap of first view:
SecondViewController *secondViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
[self.navigationController pushViewController:secondViewController animates:YES];
Case 2: If you are using storyboard but First view controller is not embedded in Navigation Controller:
1. Embed the First view in Navigarion controller
1.1. Open storyboard file and select the First View Controller
1.2. Goto Editor->Embed In-> Navigation Controller.
Then do the step Case:1's 2nd step.
Case 3: If you are using XIB files and first view is not in navigation controller.
1. For loading first view in AppDelegate.m application:didFnishLoading: method do as follows:
FirstViewController *firstViewController = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:firstViewController];
self.window.rootViewController = navigationController;
Then for pushing second view on first view button do as follows:
SecondViewController *secondViewController = [[FirstViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
[self.navigationController pushViewController:secondViewController animates:YES];
If this is not helpful, then just post what you did exactly then exact solution can be given. Because what approach you are using to load view is not mentioned in your question.
Use
[self pushViewController:yourViewController animated:YES];
instead of
[self presentViewController:yourViewController animated:YES completion:nil];
The first piece of code pushes the second view controller in the screen from right to left.
The second line of code, which is what you have probably written in your app presents the view controller modally, meaning from bottom to top.

How can I dismiss a View Controller

I am pushing a controller via:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
Once there, I cannot go back with either
[self dismissViewControllerAnimated:YES completion:nil];
or
[self.navigationController popViewControllerAnimated:YES];
what should I use to dismiss the last view ?
To where you want to dismiss and go to?
This is the root view controller right? It cannot be "dismissed".
If you have a another view controller and this VC is pushed or modally presented from the second VC it can be dismissed
Window is the base canvas and VC's are added over it and shown.
Ok from your clarification you have an initial VC with contacts and you are trying to go to next page(DetailsVC) from that contactVC and then dismiss back from there.
What you currently doing is getting the window and making your detailVC as the root VC.This way you cannot dismiss to the contacts VC.Make an instance of the detail VC in the didselectRowAtIndexpath method of contactsVC and push it using navigation controller.
Then you can pop using the method popViewControllerAnimated:
This is an excellent tutorial for you to start on
Your code is not "pushing a controller". That code is essentially what you may find in your app delegate for setting up your one initial window and view.
Calling popViewController only works after you've pushed a controller onto that same navigation controller using pushViewController, which you haven't done.
Calling dismissViewController only works after you've presented a view controller with presentViewController, which again you haven't done.
I finally left the above technique and went for the traditional:
ViewController *detailViewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
[self.navigationController pushViewController:detailViewController animated:YES];

Presenting two nested modal view Controllers but show just the last transition

I have a 1st VC (view controller) that should be modal, and it has a child modal VC that sometimes should be presented as soon as 1st VC will appear, but sometimes not.
So from a root VC I want to present 1st VC, and over the 1st VC present the child modal VC. But the user should only see the child VC modal transition (not the 1st VC).
AFAIK the 1st VC can only present a modal VC after viewDidAppear:, so I don't know how to make this possible, since when viewDidAppear: is called, the 1st VC is already visible to the user.
Don't want the user to see 2 modal transitions one after the other, but just the last modal transition, the child's one.
Any hint?
I figured out the simplest solution to this if you still haven't found a suitable one. You can use a UINavigationController to hold the 2 nested view controllers you are trying to display modally.
In the function that is meant to display the modal views you could do something like:
- (IBAction)showView3
{
ViewController2 *new2 = [[ViewController2 alloc] init];
ViewController3 *new3 = [[ViewController3 alloc] init];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:new2];
nav.navigationBarHidden = YES;
[nav pushViewController:new3 animated:NO];
[self presentModalViewController:nav animated:YES];
}
Then function in ViewController3 to dismiss it would have:
[self.navigationController popViewControllerAnimated:YES];
And the one in ViewController2 would have:
[self dismissModalViewControllerAnimated:YES];
The only issue I can see with this is aesthetics, as by default the transition from view3 to view2 is a horizontal animation but the one from view2 back to view1 is vertical. You could of course change that as well to make them all horizontal, or all vertical, or however you want.
You could have 1 modal view controller with 2 views. Then just pick which view you want to display when the view controller loads.
You should be able to put presentModalViewController anywhere you want, including viewWillAppear.
[self presentModalViewController:myModalViewController animated:NO];
edit: for anyone reading this, see my other (correct) answer, because this one isn't.

presentModalViewController and navigationController

I want to know the differences between the
[self presentModalViewController:controller animated:YES];
and
[self.navigationController pushViewController:controller animated:YES];
I have used both but still do not know or noticed the difference. when should use one of them ?
Thanks..
Basic difference :
pushViewController only works in navigation controllers
presentModalViewController works for all view controllers
navigationController is the instance of your UINavigationController, which is used by all the controller in your navigation stack (UIViewController).
Presenting a modal view is presenting a view on top of another view. You perform those typically for "tasks" that need to be started and completed in a self contained way. Read further on modal views on the apple developer guides.
Pushing a view on to the navigation controller is different where there is a logical need for navigation in the app. Say a drill down table as in the setting app of the iDevices, where there are main settings then you drill down to sub settings etc.
Whatever your questions are, if they are conceptual and generic as this I'd strongly advise you to google up "X programming guide" which will take you to the proper Apple programming guide :) X = view controller in your case
http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/Introduction/Introduction.html
if base class has it's own NavigationController then you can write:
[self.navigationController pushViewController:objMyViewController animated:YES];
if your base class has only UIViewController then use:
MyViewController * objMyViewController = [[MyViewController alloc] initWithNibName:#"MyViewController" bundle:nil];
UINavigationController * navController = [[UINavigationController alloc] initWithRootViewController:objMyViewController];
navController.navigationItem.leftBarButtonItem = nil; // make nil if you want
// to use it in next View
[self presentModalViewController:navController animated:YES];
now, MyViewController has navigation so you can -- Push -- another viewController by writing function as bellow in MyViewController.
-(IBAction)btnNext_click {
SecondViewController * objSecondViewController = [[SecondViewController alloc]initWithNibName:#"SecondViewController" bundle:nil];
[self.navigationController pushViewController:objSecondViewController animated:YES];
}

presentmodalviewcontroller navigationcontroller

I am creating a Navigation based iPhone application.
In that I have called a UiViewController using presentModalViewController. After that, the ViewController becomes visible. From that ViewController I need to call another ViewController using the sample presentModalViewController. Is this possible or not?
What do you mean by "call another uiviewcontroller"? (It really helps if you can be more detailed in your question.) If you mean, "slide in another view controller", then:
MyNewViewController *myNewViewController = [[MyNewViewController alloc] initWithNibName:#"MyNewViewController" bundle:nil];
[navigationController pushViewController:myNewViewController animated:YES];
[myNewViewController release];
...where:
MyNewViewController is the new view controller class that you want to slide in (the above code assumes you have an XIB file for the view controller class).
navigationController points to the current navigation controller. You'll have to replace it with something like [self navigationController], depending where you are in the view hierarchy.
U might be using following line to present a view controller.
//assume name of viewController which u want to present is "myViewController"
[self.navigationController presentModalViewController:myViewController animated:YES]
If you want to push an other ViewController or present an other ViewController then u will need to replace above line with following lines.
//[self.navigationController presentModalViewController:myViewController animated:YES];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:myViewController];
navigationController.navigationBarHidden = YES; //if u want to show navigation bar then remove this line
[self presentModalViewController:navigationController animated:YES];
After using above code you can present or push other view controllers within presented view controller.
Hope it will solve your problem :)