Can I use a UINavigationController as the detail view of a UISplitViewController? - cocoa-touch

I'm running into a problem with an iPad app where I would like to have UINavigationControllers in both of the views within a UISplitView. I've looked through other similar questions here, but most link to a tutorial online that doesn't completely solve the problem. Here's a 2-minute walkthrough to re-create the problem I'm having:
Create a New Project in XCode, starting from the Split View-based Application template.
Add the following NSLog statement as the first line within the DetailViewController's willHideViewController method:
NSLog(#"toolbar: %#", toolbar);
If you run the application now, the log will show that the DetailViewController's toolbar is alive and well. Now...
Open MainWindow.xib and expand the SplitViewController.
Drag a Navigation Controller from the library on top of the DetailViewController.
Expand the new Navigation Controller and change the class of the UIViewController within to a DetailViewController.
Ctrl-drag from the SplitViewController to the DetailViewController and assign it as the delegate.
Save MainWindow.xib and run the app again.
At this point, the detail view has a navigation bar and an empty toolbar. If you view the logs, you should find that the toolbar is null. Why is this? Am I missing some sort of connection in Interface Builder? Is the navigation bar the problem for some reason?
Unlike the tutorial at http://www.cimgf.com/2010/05/24/fixing-the-uisplitviewcontroller-template/, I would like to keep both the navigation bar and the toolbar (preferably with the toolbar at the top when in portrait and not visible when in landscape), so that I still have a functional "Back" button when the iPad is in portrait orientation.
Does anyone have any suggestions for fixing this problem? An example project with this sort of set-up would be ideal.

You can certainly use a navigation controller on the detail view of a split view controller. In fact, the iPad Settings app uses this approach. Probably the best way to get this setup is to create a new project in Xcode 4.x and select the "Master-Detail Application" template. It will generate a split view controller with 2 navigation controllers, one for the left view and one for the right view.
To your toolbar question, to keep things simple I would put a toolbar in the bottom. You can still put bar button items on the top navigation bar, although you can only put them in the left, middle, or right. If you need lots of items on the top bar, one way is to add a toolbar to the detail view and hide the navigation bar in the viewWillAppear event of the detail view class.
Here is an example on how to hide the navigation bar and show the toolbar:
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.navigationController.toolbarHidden = NO;
self.navigationController.navigationBarHidden = YES;
}

I've found the built-in UISplitViewController to behave badly when trying to combine it with most of the other built-in view controller subclasses. Matt Gemmell's MGSplitViewController is a lot more flexible and has worked pretty well for me, despite the odd glitches (though those are at least fixable as the source code is provided).

Related

UINavBarController connecting the same UIViewController to multiple navigation controllers

I have a storyboarded app with a chain of tableviews followed by a detail view. Kind of the classic iPhone app. There are 4 tabs and each one leads to a navigation controller.
The issue is I really want to avoid unnecessary glue code since the app is basically finished. If it was possible to connect the Search and Favorites (bottom two off the tab bar) controller as 'Root View Controllers' to the same UIViewController I would be done. However, this won't work since a view controller can only be the root view controller to one tab. So as you can see I've instituted two dummy UIViewControllers that forward you to the UIViewController in the middle. Now, unfortunately, I have to write code to make that central view controller a fake root view controller to disable the appearance of the back button, and prevent popping to the blank root when you double-tap the tab bar.
Has anyone got a more elegant solution?
This appears to be a flaw in Storyboards. One workaround would be to use simple view controllers for each navigation controller's rootViewController. Put a UIContainerView in each that points to the UIViewController you want to share.

UISearchBar on iPad table view disappearing below navigation controller bar

I'm working on a Universal app, using storyboards, and I've added a UISearchBar and a UISearchDisplayController to one of my table views. I've hooked it all up, and can search fine. The problem is when I push a new view controller onto the navigation stack. On the iPhone, this is fine, but on the iPad, it results in the pushed view controller being offset underneath the navigation bar (I had to manually make the navigation bar reappear so that you could get back).
Then, when you navigate back to the original table view where the search was taking place, the search is still active, but the UISearchBar is now hidden behind the navigation bar, meaning there is no way to dismiss it without deleting the query. It also means that it is not longer usable, since you can't get back in to it.
Probably best illustrated using some screenshots.
Here is how it looks when you first open the tableview:
Then doing the search is fine:
Clicking through to the next screen, we can see the issue:
And then back on the original screen, still doing the search but no search box:
Then, if I delete everything from the search box, and get rid of the overlay, I can see the search box when I scroll the table view up, but can never reach it. I can't get a reliable screen grab of that though.
I've looked everywhere for a solution but haven't been able to find one. I've tried calling [self setNeedsDisplay] and [self setNeedsLayout] in the viewDidAppear method, but that seems to have no effect. It seems to rectify itself if I change the orientation of the device, and I was trying to replicate what it would do in that situation by calling those methods.
The structure of the iPad storyboard is: SplitViewController -> Navigation Controller -> UITabBarController -> UITableViewController (contains UISearchBar etc.f) -> UITableViewController
I submitted this issue to Apple DTS, and they responded:
The structure of the iPad storyboard is: SplitViewController -> Navigation Controller -> UITabBarController -> UITableViewController (contains UISearchBar etc.f) -> UITableViewController
The fact is that your project architecture does not follow our guidelines which are:
From the Combined View Controller Interfaces section of the View Controller Catalog for iOS:
When combining view controllers, however, the order of containment is important; only certain arrangements are valid. The order of containment, from child to parent, is as follows:
Content view controllers, and container view controllers that have flexible bounds (such as the page view controller)
Navigation view controller
Tab bar controller
Split view controller
Basically, you should have a structure as follows:
SplitViewController -> UITabBarController ->Navigation Controller-> UITableViewController (contains UISearchBar etc.f) -> UITableViewController>

UITabbarcontroller with nested pages - cannot get tab bar control to show root

I have used UITabbar control to navigate to the top level pages of my app. Each top level page navigates to 5 other pages using command buttons to drill deeper. When the user selects the next tabbar item, instead of navigating to the root, they end up on the page they were last reading in the hierarchy. I am using XCode 4 and Tab Bars have been created using IB.
How can I change this behavior so that the tab bar button always navigates to the top level page? Your help would be very much appreciated since I have spent many days trying to resolve this issue.
I believe this will work if your tabs have UINavigationController at their root
//somewhere in the initialization process
tabBarController.delegate = self
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
UINavigationController *navController = (UINavigationController *)viewController;
if([navController.viewControllers count]>0)
[navController popToRootViewControllerAnimated:NO];
}
I have implemented UITabBar with each button loading a separate view controller and each of those view controllers having a navigation controller as a drill-down interface. When each button on the tab bar is clicked, the UIViewController is loaded and it is responsible for handling the drill down.
This sounds like what you want to do. Since I'm not sure what you mean by "page", I don't know how you are implementing the change that happens when a button is tapped on the tab bar. It sounds like you have one UIViewController and that's not quite how the UITabBar was designed to function. I could be wrong, so I think a little more explanation is needed.
If you are implementing with multiple UIViewControllers, You may want to think about whether a user is going to want to remain buried in the drill down even on changing tabs. Not sure what you App does, but this may be desired behavior.

Creating a split view application similar to 'settings' app

I am trying to build an iPad app set-up as a split-view, but on the detail page being able to drill down like a navigation controller.
An example of this working is the setting app on the iPad where if you select the 'General' tab you can then drill down on the detail page from say general > network > VPN
Any help or tips on this would be great. I thought it might be two navigation controllers on the root nib, but couldn't get this working.
you mean like General -> About ->.. (in ipad simulator) right .
if all your detail view needs the TableView, then its better to make your detailviewcontroller as the subclass of UITableViewCOntroller.
OR If you need different views when click on the cells of rootcontroller(left pane)
Create a method in DetailViewController say setDetailView{}. And call this method when click on the cell of RootController
inside this method,
remove all subviews from detailview
create UITableView and set its delegates
on tableview didSelect method, we can push other UIViewController instance
[self.navigationController push...]
Hope it helps.

Setting Toolbar Items of UINavigationController

In iPhone OS 3.0, you can set the toolbar items of a UINavigationController using the setToolbarItems:animated: method. However, this requires you pass in an array of UIToolbarItems. While I could programmatically create these toolbar items, I'd rather create them in Interface Builder if possible.
With this in mind, I have created a UIToolbar in "MyGreatViewController.xib" and have populated it with the wanted toolbar items. Then, in "MyGreatViewController.m", I get the items from the toolbar and pass them to setToolbarItems:animated::
- (void)viewDidLoad {
[super viewDidLoad];
[self setToolbarItems: [toolbar items]];
}
...where toolbar is an IBOutlet referring to the UIToolbar.
Is this a good approach? Is there a better way to accomplish this? Should I just create the items programmatically?
I don't know if this is documented anywhere, but I've found that in Interface Builder, if you enable the navigation controller's toolbar, you can drag bar items to your view controller, and they will automagically show up in the navigation controller's toolbar.
For example, here's what we can do (using Xcode 3.2 on Snow Leopard):
File->New Project.... Choose Navigation-based Application and create the project.
Open MainWindow.xib in Interface Builder.
Select the Navigation Controller, and in the Attributes inspector, check the "Shows Toolbar" box. This will cause a Toolbar object to appear.
Drag a Bar Button Item from the Library to the toolbar. It will appear in the toolbar. If you check the hierarchy in the NIB, you'll see that this new item is a child of the RootViewController.
It seems that any Bar Button Items added as children of the navigation item will show up in the navigation bar, and any Bar Button Items added as children of the view controller will show up in the toolbar.
(I stumbled on this by accident. If anyone can find documentation for this behavior, or any additional info, I'd like to hear about it.)
It's a perfectly acceptable way of doing it, but do bear in mind that loading xib files is quite expensive on the iPhone, and it may well be faster to create the toolbar items programatically in your viewDidLoad method.