So I have a tabBarController as a modalview, and it shows up fine. As I click some of the tabs, the views are loading properly. I want to dismiss the modalView when I click on tabBarController.selectedIndex ==4
So I write in the viewDidLoad and also tried in the viewWillAppear of that view controller to dismissModalViewController and it does not work.
I tried
[self.parentViewController dismissModalViewControllerAnimated:YES];
// ... And also //
[self dismissModalViewControllerAnimated:YES];
Could someone point out why it does not work ?
All you have to do is pass a reference to the modally presented VC pointing on the VC that will present it modally.
Define a weak reference as a property in the UITabBarController subclass, and send a message to dismiss it when required.
For example using a property named mainViewController :
MySubclass *tbController = [[MySubclass ....];
tbController.mainViewController = self;
[self presentModalViewController:tbController animated:YES];
Then in MySubclass define
#property(assign) UIViewController *mainViewController;
and synthesize it, then when the tab you want gets selected :
[self.mainViewController dismissModalViewControllerAnimated:YES];
I think the 4th view controller (of the tab bar controller) is trying to get dismissed by the line
[self.parentViewController dismissModalViewControllerAnimated:YES];
Since this 4th view controller was not presented by any controller, this wont work.
And it is dismissing it's modal view controller by the line
[self dismissModalViewControllerAnimated:YES];
Since, this 4th view controller did not presented any view controller, this again should not work.
You want to dismiss the tab bar controller and not its 4th view controller.
Basically, you can get the reference of tab bar controller from the 4th view controller.
As, [yourFourthViewController.tabBarController.parentViewController dismissModalViewControllerAnimated:YES];
I am guessing this without actually trying. Let me know if this works.
If you have the UINavigationController as the parent controller then the following line will work for you.
[self dismissModalViewControllerAnimated:YES];
But here I think you have the UIViewController is the parent controller instead of the UINavigationController. So, You can do one thing when presentModalViewController.
if(objView == nil)
objView = [[YourViewController alloc] initWithNibName:#"YourViewController" bundle:nil];
UINavigationController *navigationController1 = [[UINavigationController alloc] initWithRootViewController:objView];
[self presentModalViewController:navigationController1 animated:YES];
Let me know if you need more help or any questions.
Related
I had a tabbarcontroller application in which i am created that like this
UITabBarcontroller (UIWindow's rootViewController)
->UINavigationController (first tab)
-->UIViewController
->UINavigationController (second tab)
-->UIViewController
in the navigation bar i had a button in which i am pushing another view controller to the self .navigation controller.But now i want the same action from the other navigation controller also. so i need to push to the navigation controller which is the top view controller.I need to replace the [self.navigationController pushViewController:viewcontroller animated:NO]; with in a way that whichever is the navigation controller present there in the tabbar controller we need to add to that.Can any body help me on this?
Well how simpler than holding a refference to the UInavigationController that is currently visible (you should hold that refference from the UITabBarController delegate tabBarController:didSelectViewController:)
So you add in your AppDelegate a variable:
UINavigationController *navController;
then :
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
if (viewController.navigationController)
navController = viewController.navigationController;
}
Now, you do the push this way:
if (navController)
[navController pushViewController:viewcontroller animated:NO];
So at first you need have access to TabBarController. I think you can get it somewhere in AppDelegate.
then you can just call:
UIViewController *ctrl = myTabBarCtrl.selectedViewController;
[ctrl.navigationController pushViewController:viewcontroller animated:NO];
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];
}
}];
I have an app which consists of three layers of view controllers: UITabBarController => UINavigationController => UIViewController. They are all generated in code rather than using IB. The tab bar is on the bottom as per the usual design guidelines. In my UIViewController I am using this code to present the modalViewController:
myModalVC = [[MyModalViewController alloc] init];
[self.navigationController presentModalViewController:myModalVC animated:YES];
This work fine and the modal view controller pops up and covers the entire screen.
However when a button is pressed within the modal view controller, I run this:
[self dismissModalViewControllerAnimated:YES];
And the modal view controller animates away. However I can see the original UIViewcontroller view but the tab bar disappears completely. I've googled a lot but I can't find anyone that has this same problem.
You should delegate your modal view controller to your parent view controller. [self dismissModalViewControllerAnimated:YES]; should be done by the delegate and not the modal view itself, parent view are responsible for dismissing the modal view.
Actually I found this by googling a bit more. I made my tab bar controller a property of the app delegate and when it presents the modal vc, it does this
UIApplication *myApp = [UIApplication sharedApplication];
noIBAppDelegate*appDelegate = (noIBAppDelegate*)myApp.delegate;
[appDelegate.tabBarController presentModalViewController:myModalVC animated:YES];
Then it dismisses it by this bit of code
UIApplication *myApp = [UIApplication sharedApplication];
noIBAppDelegate*appDelegate = (noIBAppDelegate*)myApp.delegate;
[appDelegate.tabBarController dismissModalViewControllerAnimated:YES];
This fixes the the tab bar disappearing.
Try
[self.navigationController dismissModalViewControllerAnimated:YES];
Thanks for your answer! I had the same problem, but I'm writing in Swift, so thought I'd include my solution that I figured out from looking at yours. I only had to use these two lines to fix the problem. Nothing else was needed.
tabBarController?.presentViewController(viewController, animated: true, completion: nil)
and
tabBarController?.dismissViewControllerAnimated(true, completion: nil)
I should also mention that the line: tabBarController?.delegate = self, is in the viewDidLoad function of my NavigationController.
I am showing a modal view which is a UITableViewController class. For some reason it won't show the navigation bar when I show it. Here is my code:
SettingsCreateAccount *detailViewController = [[SettingsCreateAccount alloc] initWithStyle:UITableViewStyleGrouped];
detailViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
detailViewController.navigationController.navigationBarHidden = NO;
[self.navigationController presentModalViewController:detailViewController animated:YES];
detailViewController = nil;
[detailViewController release];
I thought it was shown by default? If it helps, I am calling this from another class that is also a UITableViewController managed by a UINavigationController. Ideas?
When you present a modal view controller it does not use any existing navigation controllers or navigation bars. If all you want is to display a navigation bar, you need to add the navigation bar as a subview of your modal view and present it as you're doing.
If you want to present a modal view controller with navigation functionality, you need to present a modal navigation controller containing your detail view controller instead, like so:
SettingsCreateAccount *detailViewController = [[SettingsCreateAccount alloc] initWithStyle:UITableViewStyleGrouped];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:detailViewController];
[detailViewController release];
navController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:navController animated:YES];
[navController release];
Your modal controller will manage its own navigation stack.
Here is one way to display navigation bar for those who are using storyboards, suggested by Apple's Tutorial on Storyboard.
Because a modal view controller doesn’t get added to the navigation stack, it doesn’t get a navigation bar from the table view controller’s navigation controller. To give the view controller a navigation bar when presented modally, embed it in its own navigation controller.
In the outline view, select View Controller.
With the view controller selected, choose Editor > Embed In > Navigation Controller.
On iOS 7 and you just want a navigation bar on your modal view controller to show a title and some buttons? Try this magic in your UITableViewController:
// in the .h
#property (strong) UINavigationBar* navigationBar;
//in the .m
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = #"Awesome";
self.navigationBar = [[UINavigationBar alloc] initWithFrame:CGRectZero];
[self.view addSubview:_navigationBar];
[self.navigationBar pushNavigationItem:self.navigationItem animated:NO];
}
-(void)layoutNavigationBar{
self.navigationBar.frame = CGRectMake(0, self.tableView.contentOffset.y, self.tableView.frame.size.width, self.topLayoutGuide.length + 44);
self.tableView.contentInset = UIEdgeInsetsMake(self.navigationBar.frame.size.height, 0, 0, 0);
}
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
//no need to call super
[self layoutNavigationBar];
}
-(void)viewDidLayoutSubviews{
[super viewDidLayoutSubviews];
[self layoutNavigationBar];
}
I want to share how the accepted solution can be used in projects with storyboards:
The simple approach is to put in a storyboard blank navigation controller before the VC which is to be presented modally, so the relations look like:
(Presenter VC) -> presents modally -> (navigation controller having a controller to be presented as its root).
We've tried this approach for a while and noticed that our storyboards become "polluted" by a large number of such intermediate navigation controllers when each! of them is used exclusively for one! presentation of some other controller, that we want to be presented modally with navigation bar.
Our current solution is to encapsulate the code from accepted answer to a custom segue:
#import "ModalPresentationWithNavigationBarSegue.h"
#implementation ModalPresentationWithNavigationBarSegue
- (void)perform {
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:self.destinationViewController];
[self.sourceViewController presentViewController:navigationController animated:YES completion:nil];
}
#end
Having this segue in our project we do not create intermediate navigation controllers in our storyboards anymore, we just use this ModalPresentationWithNavigationBarSegue like:
Presenter VC --> Presentee VC
I hope that this answer will be helpful to people who like to avoid unnecessary duplication in their apps storyboards.
I just wanted to add something to what #Scott said. His answer is definitely the easiest and most accepted way of doing it now with Storyboards, iOS 7 and 8... (and soon, 9).
Definitely adding a view controller to the Storyboard and Embedding it as described by #Scott is the right way to go.
Then, just add the segue by control-dragging from the source view controller to the target (the one you want to show modally), select "Present Modally" when the little view appears with the choices for the type of segue. Probably good to give it a name too (in the example below I use "presentMyModalViewController").
One thing that I needed that was missing is #Scott's case is when you want to actually pass on some data to that modally-presented view controller that is embedded in the navigation controller.
If you grab the segue.destinationViewController, it will be a UINavigationController, not the controller you embedded in the UINavigationController.
So, to get at the embedded view controller inside the navigation controller, here's what I did:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"presentMyModalViewController"]) {
// This could be collapsed, but it's a little easier to see
// what's going on written out this way.
// First get the destination view controller, which will be a UINavigationController
UINavigationController *nvc = (UINavigationController *)segue.destinationViewController;
// To get the view controller we're interested in, grab the navigation controller's "topViewController" property
MyModalViewController *vc = (EmailReceiptViewController *)[nvc topViewController];
// Now that we have the reference to our view controller, we can set its properties here:
vc.myAwesomeProperty = #"awesome!";
}
}
Hope this helps!
If you only need a NavigationBar, you can add an instance of UINavigationBar and assign BarItems to it.
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 :)