I have to instantiate in one of the view controllers.
UISplitViewController *splitViewController = [kStoryBoard instantiateViewControllerWithIdentifier:#"splitController"];
UINavigationController *navigationController = [splitViewController.viewControllers lastObject];
splitViewController.delegate = (id)navigationController.topViewController;
splitViewController.navigationController.navigationBarHidden = YES;
splitViewController.presentsWithGesture = NO;
UISwipeGestureRecognizer *swipeRecognizer = [[UISwipeGestureRecognizer alloc]initWithTarget:navigationController.topViewController action:#selector(swipeDetected:)];
swipeRecognizer.direction = UISwipeGestureRecognizerDirectionLeft|UISwipeGestureRecognizerDirectionRight;
[splitViewController.view addGestureRecognizer:swipeRecognizer];
CGRect frame = splitViewController.view.frame;
frame.origin.x = 0;
frame.size.height -=100;
frame.origin.y +=100;
splitViewController.view.frame = frame;
UINavigationController *masterNavigationController = [splitViewController.viewControllers objectAtIndex:0];
MasterViewController *masterVC = (MasterViewController*)[masterNavigationController topViewController];
masterVC.currentCategory = [categoriesArray objectAtIndex:sender.tag-1];
self.navigationController.navigationBarHidden = YES;
[self.navigationController setViewControllers:[NSArray arrayWithObject:splitViewController] animated:YES];
My app crashes on this line.
[self.navigationController setViewControllers:[NSArray arrayWithObject:splitViewController] animated:YES];
It is working fine for ios 5 and ios 6.
Crash occurs only in ios 7.
This is the error.
[UINavigationController _setViewControllers:transition:animated:], /SourceCache/UIKit/UIKit-2903.2/UINavigationController.m:768
2013-10-21 18:51:37.009 TruAirSync[1723:60b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UISplitViewControllers are not allowed in a navigation controller!'
Found the answer.
Hope it will help others also.
We just need to use a view controller.
UIViewController *containerVC = [[UIViewController alloc]init];
[containerVC.view setFrame:splitViewController.view.frame];
[containerVC.view addSubview:splitViewController.view];
[containerVC addChildViewController:splitViewController];
[splitViewController didMoveToParentViewController:containerVC];
[self.navigationController setViewControllers:[NSArray arrayWithObject:containerVC] animated:YES];
Just create another UIViewController and add you splitviewcontroller's view to it's subview than you can use it in a UINavigationController.
YourContainerController *containerController = [YourContainerController new];
[containerController.view addSubview:splitViewController.view];
[self.navigationController setViewControllers:#[containerController] animated:YES];
The UISplitViewController should be the root view of your application window. Not sure why this was working for you in iOS 5 and 6. You can not push a UISplitViewController into a UINavigationController.
From Apple's documentation:
A split view controller must always be the root of any interface you
create. In other words, you must always install the view from a
UISplitViewController object as the root view of your application’s
window.
Related
We have a UINavigationViewController as root viewController in AppDelegate:
Restore *callRestore=[[Restore alloc]initWithNibName:#"Restore" bundle:nil];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:callRestore];
self.window.rootViewController = self.navigationController;
We are pushing a new viewController (TabViewController) from above Restore:
callTabView=[[TabViewController alloc] initWithNibName:#"TabViewController" bundle:nil];
[self.navigationController pushViewController:callTabView animated:YES];
In this TabViewController we are adding UITabBarController programatically as subview and in this UITabBarController we have 5 UINavigationBarController as view controllers:
NSArray* controllers = [NSArray arrayWithObjects:navControllerDashboard, navControllerAccounts, navControllerTransation,navControllerCallDisplayReports,navControllerMore, nil];
self.tabBarController.viewControllers = controllers;
self.tabBarController.delegate = self;
self.tabBarController.view.frame = self.view.frame;
[self.view addSubview:self.tabBarController.view];
When we are rotating any view from these 5 UINavigationViewController we are getting 2 UINavigationBar on top in both landscape and portrait mode.
Check below image.
and didRotateFromInterfaceOrientation is not calling from these 5 UINavigationViewController view.
Any help?
When you add a view controller to another one as a subview manually you have to do the following:
UIViewController *parent = ...;
UIViewController *child = ...;
[child willMoveToParentViewController: parent];
[parent addChildViewController: child];
[parent.view addSubview: child.view];
[child didMoveToParentViewController:parent];
This will propagate all the events to the child view controller and possibly remove unexpected behaviour.
I am updating an old app to the new adaptive size way of doing things and having difficulty getting a popover with a navigation controller to work.
My goal: I want to be able to open a popover from a button when the app is either compact and regular horizontal. The popover has a tableview and uses a navigation controller to push view controllers when the user touches a row on the table. I can get the popover to open correctly, but I can’t figure out who to make the pushes work.
Here’s the code that opens the popover:
OptionsController *vc = [[OptionsController alloc] initWithNibName:#"OptionsView" bundle:nil];
vc.modalPresentationStyle = UIModalPresentationPopover;
UIPopoverPresentationController *popover = [vc popoverPresentationController];
popover.delegate = self;
[self presentViewController:vc animated: YES completion: nil];
popover.permittedArrowDirections = UIPopoverArrowDirectionUp; // change as necessary
popover.sourceView = self.view;
CGRect popoverRect = [self.view convertRect:[sender frame] fromView:[sender superview]];
popover.sourceRect = popoverRect;
This code correctly opens a popover in either compact or regular size.
In the OptionsController’s didSelectRowAtIndexPath method, I have this(controllersArray is an array of UIViewControllers, each of which corresponds to a row in the table):
UIViewController *nextController = [self.controllersArray objectAtIndex: [indexPath row]];
[self.navigationController pushViewController:nextController animated:YES];
All this executes, but no push occurs, so the next view never appears.
I clearly am not understanding something about using the UIViewController’s navigationController, or how to install a navigationController to make this work. After three or four days of digging around to try to understand how to make this work, I'd appreciate any insights, or links to documentation about how to do this. Thanks in advance.
Crud - this has a very easy answer. Just took me thinking a different way and digging through Larcerax's comments. Here's how to make this work:
OptionsController *vc = [[OptionsController alloc] initWithStyle:UITableViewStylePlain];
vc.title = #"Options";
UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController: vc];
nc.modalPresentationStyle = UIModalPresentationPopover;
UIPopoverPresentationController *popover = [nc popoverPresentationController];
popover.delegate = self;
[self presentViewController:nc animated: YES completion: nil];
popover.permittedArrowDirections = UIPopoverArrowDirectionUp; // change as necessary
popover.sourceView = self.view;
CGRect popoverRect = [self.view convertRect:[sender frame] fromView:[sender superview]];
popover.sourceRect = popoverRect;
The difference is that I create the UINavigationController in the usual manner...
UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController: vc];
...set the navigationController's presentation style to popover, then get the popoverPresentationController from the navigationController - before I was doing those two methods on the UIViewController.
nc.modalPresentationStyle = UIModalPresentationPopover;
UIPopoverPresentationController *popover = [nc popoverPresentationController];
Finally, I present the navigationController:
nc.modalPresentationStyle = UIModalPresentationPopover;
UIPopoverPresentationController *popover = [nc popoverPresentationController];
This approach presents a popover, in compact and regular horizontal sizes, that contains navigation controller functionality: just what I wanted.
Thanks again to Larcerax whose answer wasn't what I needed, but made me re-think what I was doing in a different way. As usual, StackOverflow comes through.
Here's what you should try. I use about 10-40 navigation controllers per app for the apps I work on and I've had this same sort of issue, I've not used popovers, but I've subclassed the crap out of navigation controllers and view controllers to have encountered your same problem. The thing is that if you do this:
UIViewController * ff = [UIViewController new]
[self presnetViewController:ff ... blah blah blah
There is apparently NO navigation system attached to the modal view controller and therefore you can't navigate to anything else, you can only close the modal and move on. So, this is what I do to resolve this and it works everytime, well it works everytime for UIViewControllers, give it a shot
see the following, it's not for popovers, but the principle is the same:
NSHTermsOfServiceViewController * pvc = [NSHTermsOfServiceViewController new];
UIBarButtonItem * backBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"exit-button"] style:UIBarButtonItemStylePlain target:self action:#selector(backerPressed)];
NSHNavigationController * ssf = [[NSHNavigationController alloc] initWithRootViewController:pvc];
[[pvc navigationItem] setLeftBarButtonItem:backBarButtonItem];
[[self navigationController] presentViewController:ssf animated:true completion:nil];
NSHTermsOfServiceViewController <== is a subclass of another subclass of a UIViewcontroller, it's basically a UIViewController on steroids, that's all
NSHNavigationController is a UINavigationController that is subclassed and pumped up on steroids for animations
The flow is this:
create a viewController
create a new UINavigationController
Set the view controller you created in step 1 as the root view controller of the navigation controller created in step 2
present the NAVIGATION CONTROLLER, not the UIViewController, you can present this navigationController from a view controller like so ..
v
[self presentViewController:ssf animated:true completion:nil];
or you can present it from the current view controller's navigation controller which is what I prefer, like so:
[[self navigationController] presentViewController:ssf animated:true completion:nil];
Your code, modified, the only problem is that I don't know if you can present a UIPopOverViewController by rooting it inside a navigation controller
OptionsController *vc = [[OptionsController alloc] initWithNibName:#"OptionsView" bundle:nil];
UIPopoverPresentationController *popover = [vc popoverPresentationController];
UINavigationController * stuff = [[NSHNavigationController alloc] initWithRootViewController:popover];
stuff.modalPresentationStyle = UIModalPresentationPopover;
stuff.delegate = self;
[self.navigationController presentViewController:stuff animated: YES completion: nil];
popover.permittedArrowDirections = UIPopoverArrowDirectionUp; // change as necessary
popover.sourceView = self.view;
CGRect popoverRect = [self.view convertRect:[sender frame] fromView:[sender superview]];
popover.sourceRect = popoverRect;
Yep, my bad, doesn't work for popover, I just tried it
So, with that said, is it absolutely necessary to use a popover? Why are you using this and now just a UIViewcontroller that you reconfigure to look like a popover and then you have what you need?
Here's this, I just tried it with the Ipad simulator, and it allowed a push, just as it should have.
NSHLoginViewController * pvc = [NSHLoginViewController new];
UINavigationController *navController = [[UINavigationController alloc]initWithRootViewController:pvc];
UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:navController];
UIView * stuff = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 1000, 1000)];
[self.view addSubview:stuff];
[popover presentPopoverFromRect:[[self contentView] nameField].frame inView:stuff permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
this: [[self contentView] nameField].frame is just a uitextfield, nothing special, that's all, and the method above presented the login viewcontroller, when I put in my credentials, I pressed log in and it pusehed the next viewcontroller as it normally would, there's probalby something wrong with the touches being intercepted by your uitableview or whatever, perhaps not, but this method did work for me.
I am developing a ViewController (login app) with a single button, when I press this button I want to appear my UISplitView like this:
- (IBAction)loadSplitViewController:(id)sender {
[self showSplitViewController];
}
and the code developed for the creation of my splitViewController is this:
-(void)showSplitViewController{
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPad" bundle: nil];
LeftViewController *leftViewController = [mainStoryboard instantiateViewControllerWithIdentifier:#"LeftViewController"];
RightViewController *rightViewController = [mainStoryboard instantiateViewControllerWithIdentifier:#"RightViewController"];
UINavigationController *leftNavController = [[UINavigationController alloc] initWithRootViewController:leftViewController];
UINavigationController *rightNavController = [[UINavigationController alloc] initWithRootViewController:rightViewController];
UISplitViewController *splitViewController = [[UISplitViewController alloc] init];
splitViewController.viewControllers = [NSArray arrayWithObjects:leftNavController, rightNavController, nil];
leftViewController.delegate = rightViewController;
splitViewController.delegate = rightViewController;
[self presentViewController:splitViewController animated:YES completion:^{}];
}
the thing is... if I use for display my splitViewController this line:
[self presentViewController:splitViewController animated:YES completion:^{}];
throws me an error
I also tried with
[self.view addSubview:splitViewController.view];
but this way my splitViewController never rotates, and delegates doesn't work as well... and I don't want my splitViewController to be a subview of my viewController, I want it to appear more like an independient modalView
any help I'll appreciate
thanks in advance
Split view controllers really should be the root view controller of the window (in fact Apple says it has to be, though there seem to be some examples where this isn't true). Instead of presenting it, you could just switch the window's root view controller to be the split view controller.
self.view.window.rootViewController = splitViewController;
I have a problem trying to access a navigation controller of the view controller from it, always returns as nill to me, though it is shown within the navigation controller.
Here is what I have (I have a split view controller, that is presented as tab controller for master and viewcontroller (inside navigation controller) as detail):
FirstDetailViewController *fdvc = [[FirstDetailViewController alloc] initWithNibName:#"FirstDetailViewController" bundle:nil];
UINavigationController *fdvcNav = [[UINavigationController alloc] initWithRootViewController:fdvc];
NSArray *ipadVCs = [[NSArray alloc] initWithObjects:tabController, fdvcNav, nil];
UISplitViewController *splitvc = [[UISplitViewController alloc] initWithNibName:nil bundle:nil];
[splitvc setViewControllers:ipadVCs];
[[splitvc view] setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"splitViewControllerBG"]]];
[splitvc setDelegate:fdvc];
[[self window] setRootViewController:splitvc];
[[self window] makeKeyAndVisible];
But when I'm trying to access a navigation controller from the fdvc view controller in ViewDidLoad with [self navigationController] it gives me (Null) always.
Thanks!
I fixed it. Turned out, that I had to move my code from ViewDidLoad method to ViewDidAppear and it worked fine.
viewDidLoad is getting called before the navigationController property has been updated, that was my mistake.
I have ViewController with child, it's works great, but when I change root view to another, and then return back the root view:
-(void)showSearchResultView
{
self.searchView.frame = self.view.frame;
__rootView = self.view;
[self setView:self.searchView];
}
-(void)hideSearchResultView
{
if(__rootView) [self setView:__rootView];
__rootView = nil;
}
I'm getting the exception:
Terminating app due to uncaught exception 'UIViewControllerHierarchyInconsistency',
reason: 'child view controller:<SlideViewController> should have parent view controller:
<UINavigationController> but actual parent is:<MainViewController>'
What is the proper way to change root view with child view controllers?
For changing root view you have to remove rootviewcontroller from navigation stack.
Like :
NSMutablerray *controllers = [self.navigationController viewcontrollers];
[controllers removeObjectAtIndex:0];
it will remove the rootviewController and name way you can add new view Controllers.
[controllers addObjectAtIndex:0];
Note:- This code syntax might be incorrect .this is just a approach.
Update:-
NSMutableArray *viewControllers = [[NSMutableArray alloc]initWithArray:self.navigationController.viewControllers];
RootViewController *root = [[RootViewController alloc]initWithNibName:#"RootViewController" bundle:nil];
[viewControllers insertObject:root atIndex:0];
self.navigationController.viewControllers = viewControllers;
This way you can change your root view.
I found the solution. Just remove the children root views and add it again.
-(void)showSearchResultView
{
self.searchView.frame = self.view.frame;
__rootView = self.view;
[self setView:self.searchView];
for(UIViewController* vc in self.childViewControllers){
[vc.view removeFromSuperview];
}
}
-(void)hideSearchResultView
{
if(__rootView) [self setView:__rootView];
__rootView = nil;
for(UIViewController* vc in self.childViewControllers){
vc.view.frame = self.view.bounds;
[self.view addSubview:vc.view];
}
}