I have moved from UITabBar to split view on my iPad application.
The view controllers are sent by the master to the detail which puts them into a UINavigationController.
// Detail manager called when a cell is selected on the master
UINavigationController *detailNavigationController = [[UINavigationController alloc] initWithRootViewController:_detailViewController];
UIViewController *mainNavigationViewController = [self.splitViewController.viewControllers objectAtIndex:0];
NSArray *viewControllers = [[NSArray alloc] initWithObjects:mainNavigationViewController, detailNavigationController, nil];
self.splitViewController.viewControllers = viewControllers;
Now every time a cell on the master is selected, the navigation controller on the detail view starts from the root.
Instead I would like to have the same behavior of the tab bar controller: when you move from one tab to another, the navigation stack for each tab is maintained. And when you select two times the same tab, the navigation stack pops to the root view controller.
How to implement this in a proper way with a split view based application?
You should make a navigation controller for each cell in the master table. When tapping a cell, you switch it accordingly. If the selected cell is tapped, you call popToRootViewController:animated: on the visible navigation controller. Of course, you have to subclass UISplitViewController to keep a reference to your navigation controllers. You would also have to create a MaterTableDelegate to tell you split VC, he should change the navcon in the detail side.
Starting from the suggestions of Levi I implemented a working solution.
To summarize:
Subclass UISplitViewController
Create on it a public reference to each UINavigationController you need
Inside the init of your UISplitViewController subclass initialize all the navigation controllers with their respective root UIViewControllers
According to your master-detail implementation, make sure that every time you select a cell in the master view, the right navigation controller (among all the one you have declared on your UISplitviewcontroller subclass) is presented on the detail view. I managed this with an NSinteger property on the detail manager (set on master cell selection) to tell it which navigation controller to present on the detail view.
If the same master view cell is selected twice, pop the corresponding navigation controller to root to simulate the same UITabBar behavior.
Hope this will help someone.
Related
I've read several posts about this issue, but I've been troubleshooting and the previous solutions don't seem to do the trick (i.e. the solutions specify embedding only the parent controller in the navigation controller, which I've tried). To address it as per previous posts, I've removed the embedding of the other views in their own navigation controllers -- but can't then seem to physically draw the segue from one table view to another; or it doesn't show the back button...
Basically, the "Back" button disappears on segue. It isn't seen in the second TableViewController and the last ViewController (on the end). It reappears in the parent, obviously.
EDIT: When I remove the navigation controller from the other two views, then no navigation bar appears on those VCs at all. The bar completely disappears, although it appears on the first one. This is how I have it configured now.
New Storyboard
Navigation Controller follows the Stack theory. When you push something in the stack it will increment the top index count by 1 and pop something in the stack it will decrease the top index count by 1.
In the navigation controller, first controller will be your root viewController. Now When you push new view controller in navigation controller, your top index count will be 2. But you are not pushing the viewController in same navigation controller (let say Stack1) you are creating the new Navigation controller (let say Stack2).
So here you are setting the new controller as the root viewController for new navigation controller(Stack2) and there are no item to pop yet that is why it's not showing the back button.
To Solve these Problem remove the navigation controller from the second and third view controller.
To push you can use segue or you can do it programmatically.
Swift
let vc2 = self.storyboard?.instantiateViewControllerWithIdentifier("ViewController2") as? ViewController2
self.navigationController?.pushViewController(vc2!, animated: true)
Objective C
ViewController2 *vc2 = [self.storyboard instantiateViewControllerWithIdentifier:#"ViewController2"];
[[self navigationController] pushViewController:vc2 animated:YES];
Navigation Controller Guideline
Edit
if you are not able to see the navigation bar on second VC
Make sure you are not hiding it by code in second VC.
Make sure you are pushing the second VC not presenting the VC.
Select VC in Interface Builder -> Attribute Inspector -> Top bar should be inferred.
if you are using segue then segue type(kind) should be Show.
Is it possible to start your project with a single view controller, then on the second or third view controller implement the navigation controller, then maybe on the forth view controller implement the tab view controller? Or does this type of project need to be a storyboard project?
My dilema at the moment is that I start with just one single view controller that has a round rect button that takes you to the second view controller. From the second view controller, I would like a navigation controller with an embedded table view that will take me back and fourth from the second to the third view controller. I've been trying for hours putting the necessary code into each .h and .m file but I keep hitting brick walls.
Thanks in advance.
a. You can of course present several regular view controllers then add a UINavigationController at a later stage. When you need to present the navigation controller, you can embed your detail view controller inside one as follows:
(code is in the view controller which you want to display the detail view controller from)
DetailViewController *detailVC = [[DetailViewController alloc] init];
UINavigationController *detailNav = [[UINavigationController alloc] initWithRootViewController:detailVC];
[self presentViewController:detailNav animated:TRUE completion:nil];
b. It is not allowed to have a UITabBarController inside a UINavigationController (or any other view controller). You can however still use the UITabBar control and manage the rest. For an example of this, please refer to UITabBarController inside a UINavigationController.
I have a SplitViewController which has two UITableViewControllers - one master/root one detail. Everything works swimmingly.
I have a UIView which is shown on the detail view controller before the user selects an item in the root view controller. It's set up like this:
[self.navigationController.view addSubview:makeSentenceHelperView];
[self.navigationController.view bringSubviewToFront:makeSentenceHelperView];
The detailViewController is set up like so:
UINavigationController *detailNav = [[[UINavigationController alloc] initWithRootViewController:detailViewController] autorelease];
Where detailViewController is a subclass of UITableView.
The problem is that this subView hides the buttons and navigation bar from the detail view controller's navigation bar - which is a problem when you launch the SVC in portrait mode (there's no way to select a root item with the root popup).
How can I present the view inside the navigation controller, so that the navigation bar and buttons appear in the detail view?
Don't make detailViewController a subclass of UIView, instead go with UIViewController. So your splitView array will contain a instance of UINavigationController(rootVC) and other of UIViewController (detailVC).
Add a toolbar on the top of detailViewController and in landscape mode left side will be covered by your UITableView of rootVC and you will be able to see toolbar where you can add some button to its right side (will probably serve as navigation bar..:) . Rest of the things can be handled by UISplitViewControllerDelegate.
To fix this I added a UINavigationController to my helper UIView, and added a UIButtonBarItem to call the popover for selecting a new item in the master view. It seems really simple in retrospect. The only tricky bit will be making the UIButtonBarItem hide when in landscape.
I add 6 navigation controllers to UITabBarController's viewControllers. As normal, a More tab is created to list the last two. The problem is: after I select a table cell in the More table view, that cell's content fade out and disappear before the view controller push in. And then, after I back to the More table view by click the Back button, that cell's content show again. I guess the reason is More table view in its own navigation controller, and it push another navigation controller (created by me). I don't want to remove my navigation controller because I want to allow user rearrange tabs using the UITabBarController's Edit function. Can anyone suggest what I should do?
Create instances of your 6 navigation controllers in AppDelegate and retain them. And release in dealloc method
Just had the same problem. In my case I accidentally assigned the tabBarItem to the VC inside the navigation controller. When I instead initialized the tabBarItem on the navigation controller, the flickering / disappearing stopped.
MyViewController* viewController = [[MyViewController alloc] init];
UINavigationController* navigation = [[UINavigationController alloc] initWithRootViewController:viewController];
[viewController release];
// this has to be navigation.tabBarItem (not viewController.tabBarItem)
[navigation.tabBarItem initWithTitle:#"Title" image:[UIImage imageNamed:#"fancy.png"]
tag:42];
Initializing the tabBarItem on the viewController still showed the icon which made it harder to discover. I'm also not very sure (actually I think it's bad) about the way I initialize the tabBarItem (without alloc). But I had troubles with disappearing icons etc and hey, it works ;-)
I'm having trouble merging the two concepts of using a SplitViewController in my main view and having the "RootView" controller that controls the left panes popup/sidebar table view.
I want to have the left "RootView" act as a navigation menu, but how do I do this when the RootView is tied through MainWindow.xib into the left pane of the SplitView?
Basically, I want the left navigation to work just like the built-in email applications folder drilldown navigation. Is there an example iPad project out there that uses both SplitView and a NavigationView for the left/Root pane?
After you create a SplitView project, open up the RootViewController.m file and look at the -tableViewDidSelectRowAtIndexPath method. You'll see that the item that you clicked is then set as a property of the DetailViewController.
The design you're looking for would require that you push another view controller onto the navigation stack. So if you imagine the e-mail application, when a user picks a folder, the detailView is not updated, but the next level of the Inbox is pushed onto the stack. When a user selects a message from the inbox, the detail view is updated with the message contents, and the RootViewController just stays where it's at.
in the -tableViewDidSelectRowAtIndexPath method, declare your new view controller
NextViewController *nextView = [[NextViewController alloc] initWithStyle:UITableViewStylePlain];
//This assumes you have another table view controller called NextViewController
//We assign it to the instance variable "nextView"
[self.navigationController pushViewController:nextView animated:YES];
//tells the navigation controller to "slide" the "nextView" instance on top
//if animated:NO it wouldn't slide, it would just "update"
[nextView release];
//release the viewController, it's now retained automatically by the NavigationController
Does this make sense?