UISplitViewController, MultipleDetailViews with Navigation Controller

this tutorial shows how to have navigation controller in both master view and detail view of UISplitViewController.

Created new project with splitview template in Xcode.
Now first remove splitviewcontroller in mainwindow.nib,since we are creating split view controller programmatically .now in your appDelegate method

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
 
    // Override point for customization after app launch.
        self.splitViewController =[[UISplitViewController alloc]init];
	self.rootViewController=[[RootViewController alloc]init];
	self.detailViewController=[[FirstDetailViewController alloc]init];
 
	UINavigationController *rootNav=[[UINavigationController alloc]initWithRootViewController:rootViewController];
    UINavigationController *detailNav=[[UINavigationController alloc]initWithRootViewController:detailViewController];
 
	self.splitViewController.viewControllers=[NSArray arrayWithObjects:rootNav,detailNav,nil];
	self.splitViewController.delegate=self.detailViewController;
 
    // Add the split view controller's view to the window and display.
    [window addSubview:self.splitViewController.view];
    [window makeKeyAndVisible];
 
    return YES;
}

this will make master and detail of splitview as navigation controller.

Make two detail view controller first and second.

the main code for replacing detail navigation stack with view controller is

- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
 
    /*
     When a row is selected, set the detail view controller's detail item to the item associated with the selected row.
     */
	NSUInteger row = indexPath.row;
    [self.appDelegate.splitViewController viewWillDisappear:YES];
	NSMutableArray *viewControllerArray=[[NSMutableArray alloc] initWithArray:[[self.appDelegate.splitViewController.viewControllers objectAtIndex:1] viewControllers]];
	[viewControllerArray removeLastObject];
 
    if (row == 0) {
		self.firstDetailViewController=[[[FirstDetailViewController alloc] init]autorelease];
		[viewControllerArray addObject:self.firstDetailViewController];
		self.appDelegate.splitViewController.delegate = self.firstDetailViewController;
 
	}
 
    if (row == 1) {
		self.secondDetailViewController=[[[SecondDetailViewController alloc]init]autorelease];
		[viewControllerArray addObject:self.secondDetailViewController];
		self.appDelegate.splitViewController.delegate = self.secondDetailViewController;
    }
	[[self.appDelegate.splitViewController.viewControllers objectAtIndex:1] setViewControllers:viewControllerArray animated:NO];	
 
	[self.appDelegate.splitViewController viewWillAppear:YES];
	[viewControllerArray release];
 
   }

done You can download the code below
so now you have both of your view controller of UISplitViewController with navigation controller
MultipleDetailViewsWithNavigator

 

32 Comments

VirajMarch 16th, 2011 at 12:02 pm

Hello Kshitiz Ghimire, The link to the sample code appears to be broken.
Can you fix it ?
Thanks for the tutorial.

adminMarch 16th, 2011 at 12:21 pm

done , thank you for letting me know

ashMarch 23rd, 2011 at 10:18 am

hello kshitiz ..this is an amazing post. but in this once i selected a view from a popovercontroller, the root button disappears and we will not go back to another view . do u know how to fix it?

adminMarch 24th, 2011 at 4:07 pm

Fixed now

JánosApril 29th, 2011 at 12:56 am

Hey!

I get an runtime error in the below method, because toolbar is not exist.

– (void)splitViewController:(UISplitViewController *)svc willShowViewController:(UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem
{
NSMutableArray *items = [[self.toolbar items] mutableCopy];
[items removeObjectAtIndex:0];
[self.toolbar setItems:items animated:YES];
[items release];
self.popoverController = nil;
}

JánosApril 29th, 2011 at 12:58 am

actually the function is in DetailViewController.m

YUVARAJ.MJune 1st, 2011 at 6:55 pm

Great Post. Thank you my friend. You saved my day.

JanJune 8th, 2011 at 1:01 pm

Hello

thx for this post!
I am a newbi and so i have a question ;-)

what is this code snippet in the file FirstDetailViewController.m on top doing? is it a composition? but of what… i do not understand and way you do not the same in the SecondDetailViewController.m

@interface FirstDetailViewController ()
@property (nonatomic, retain) UIPopoverController *popoverController;

@end

thx you

adminJune 9th, 2011 at 12:30 am

hi it is same thing as second detailviewcontroller , just a different way. you can follow any way. actually when you you use default template from code it does in that way , but it is your choice

BalaJuly 19th, 2011 at 1:37 pm

Hello
Thx for this post!.I faced one problem,When i click inside Popover it does not close popover.
[popoverController dismissPopoverAnimated:YES];

delegate not working properly.Can you help me this problem

BalaJuly 31st, 2011 at 2:36 am

Hello Kshitiz Ghimire,
When i click inside Popover it does not close popover.
[popoverController dismissPopoverAnimated:YES];

delegate not working properly.Can you help me this problem.

Please provide any steps .
Can you update from your end

AlbertoAugust 3rd, 2011 at 7:33 pm

Does anyone solved the problem of dismissing the popover?
Thank

DaveSeptember 9th, 2011 at 8:31 pm

This approach works very well, thanks! Unfortunately, I too am unable to figure out how to dismiss the popover. I understand that I must keep a reference to the popover somewhere so that I can send it the dismiss message.

What I can’t figure out is where/how to create and store the reference to the popover controller when used with this approach. Where is the popover actually initialized: appDelegate, rootViewController, or in the detail view controllers? As noted above, sending dismiss to the property of the detail views does not seem to work.

DaveSeptember 10th, 2011 at 6:40 am

Ok, figured it out. Well… found a way that works, can’t say that it’s best.

The problem with the sample as it stands is that nothing actually sets the popoverController property of the detail view to point to the actual popover controller. So, you can call dissmiss on this all day long and nothing will happen; its nil.

The example implements two methods of the splitviewcontrollerdelegate protocol in each detail view controller. The trick is to implement the third method of this protocol, “willPresentViewController”. This method is called whenever the popover is displayed. Inside your implementation of this method, set the popoverController property of your class to the “pc” that gets passed to this method. Now your property actually contains a pointer to the real popover controller.

Back in whatever part of your code that will switch a detail view, before you switch the view, grab the value of the current detail view’s popoverController property.

[[[[self.splitViewController.viewControllers objectAtIndex:1] viewControllers] objectAtIndex:0] popoverController];

This points to the active pc, so you can actually send the dismiss message to it. I can’t claim that any of this is elegant or “best practice” but its working for me.

SantieSeptember 13th, 2011 at 9:32 pm

im new to the uisplitviewcontroller concept so please bare with my ignorance.

i’m struggling to understand the relationship/hierarchy of the different controllers when using the splitviewcontroller (ie. relationship between the splitview, rootview, detailview, navcontroller…)

i GET that the splitviewcontroller holds two viewcontrollers: one for the navigation controller (for rootview) and another for the detailview controller. but what i need is a bit more complex…

given a list of options (rootviewcontroller), how would i add a uinavcontroller for each option? so every option has it’s own stack of detail views

here’s what i need
ROOTVIEW
|— OPTION 1
|— (uinavigationcontroller)
| |OPT1_DETAILVIEW
| |– OPT1_DRILLDOWNVIEW1
| |–OPT1_DRILLDOWNVIEW2
| |–etc
|— OPTION 2
|— (uinavigationcontroller)
| |OPT2_DETAILVIEW
| |– OPT2_DRILLDOWNVIEW1
| |–etc
|— OPTION 3, etc

CAN SOMEONE HELP ME PLEASE!!!!

PS: i’ve looked at NUMEROUS examples and none of them cater for my requirement [or I’m dumb]! FYI -neither apple’s multipleview sample nor MGSplitview helped

oSeptember 26th, 2011 at 10:21 am

Does anyone solved the problem of dismissing the popover?
I use this project for my first project.
Please help me.
Thank you very much.

PriyankaOctober 5th, 2011 at 1:55 pm

How to dismiss the popover?

iOSDevOctober 28th, 2011 at 7:42 pm

This answer was very helpful. thanks !!

Cal LightmanApril 21st, 2012 at 4:31 am

This is nice. However, the rotations are not animated. It seems like the rotations are completed almost immediately and only the status bar rotation gets animated. Is there any way to match the rotation speed and duration of the status bar?

Cal LightmanApril 21st, 2012 at 4:42 am

Sorry about my last comment. It’s not happening anymore…

Willie KingMay 9th, 2012 at 8:35 am

Hi
For an universal iOS app (iPad and iPhone) Is it possible to make the iPad version the only device to support auto-rotate?

the iPhone will NOT support auto rotate.

is this possible or not?

adminMay 15th, 2012 at 5:13 pm

ya thats possible, just detect the device and return supported interface orientation in shouldautorotate method in view controller

Amit PatelJuly 16th, 2012 at 2:31 pm

HEllooo Frndz……!!!

I have to use UISplitViewController.and i want to add UISplitViewController to UINavigationController. bt i can’t do this..and display message in Consol..”Application tried to push a nil view controller on target .”…….so PLZ…give me answer for how to add UINavigationController to UISplitViewController…Thanx Friend…:)

DanielJuly 30th, 2012 at 10:55 pm

Hi…

Now I have this problem since a week ago and until now I understand how it is handling. thank you very much indeed for your contribution, you saved my life, not only me but several of us. Greetings from Mexico.

ghouseAugust 9th, 2012 at 6:22 pm

hi i followed your tutorial and try to implement my own stuff like in one of the second detailview i have a button when i click on it it should push to new view controller but with the same row selected .it does but when i select another row there i am getting naviagtion button which leads to second view . why it is coming like that please help me i am looking for solution for many days

mementoAugust 22nd, 2012 at 3:34 pm

Hello !
Fantastic work !

This is exactly what I needed.
But could you give me a hint, if you’re patient enough, Could you tell me what is the simplest way to push a new view controller in the detail view ?

I tried different ways in the RootViewController.m, but I think I got it wrong.

I know this question must seem dumb to you, but I’m a beginner at iOS programming.
It would be so nice of you to answer this question. :)

Alex.

mementoAugust 22nd, 2012 at 3:38 pm

To be as clear as possible, let’s say I want to put a button on the first view controller that will trigger the action of pushing another view in the detail view.

To be honest, I’m trying to push some view controllers (forms for the user) in the detail view.

Greetings from France.

SarathAugust 24th, 2012 at 10:30 am

Hi.

I have a problem with Popover window on 5.1 simulator. Normal typical popover window is displaying properly for 4.3 & 5.0 Simulator, But 5.1 Simulator at portrait mode displaying just like splitwindow…

if any one solved this problem ps tell…….

DanielAugust 31st, 2012 at 5:49 am

Great example. It is what I need. Just I have one question. I’ve read a lot about delegates, because I can’t completely understand that concept. What I read, is “delegates” are methods declared inside a protocol. The class that declares that “delegate” need to implement that methods. In this example. you don’t declare any protocol, but declare references to your AppDelegate in every ViewController. Is this because in you AppDelegate are declared the SplitViewController?
Thanks

UsmanMarch 21st, 2013 at 5:24 pm

Unfortunately, I too am unable to figure out how to dismiss the popover. plz help

UsmanMarch 22nd, 2013 at 5:01 pm

hi, I Have Solved both situations…

1) id didSelectRowAtIndexPath of RootViewController
[[NSNotificationCenter defaultCenter] postNotificationName:@”MASTERROWSELECTED”
object:nil];

2) then in FirstDetailViewController ‘s viewWillAppear and SecondDetailViewController ‘s viewDidLoad

[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(dismissPop) name:@”MASTERROWSELECTED” object:nil];

self.navigationItem.leftBarButtonItem = appDelegate.rootPopoverButtonItem;

also implement – (void)dismissPop
{

if(self.interfaceOrientation == UIInterfaceOrientationPortrait)
{

//self.popover is your reference to master view pop
if([self.popoverController isPopoverVisible])
{
[[self navigationItem] setLeftBarButtonItem:self.appDelegate.rootPopoverButtonItem ];
[self.popoverController dismissPopoverAnimated:YES];

}
}

}

before these
set
self.appDelegate.rootPopoverButtonItem = barButtonItem;

in splitViewController of FirstDetailViewController

working perfect for me…..might be not the best practice

AviOctober 31st, 2013 at 8:30 pm

Thank u very much, this is very helpful :)

Leave a comment

Your comment