I was recently displaying a list of items to a user via a tableview in a popover when a button was tapped. The table was displayed sections and headers.
I'm experimenting now with different ways to display the information and I want to try display the data in a UISplitViewController. The left view is a tableviewcontroller with headings. The right view is also a tableviewcontroller with sub headings.
I still want the data to be provided in a popover manner but when I've tried this the popover appears with nothing in it. I've put breakpoints in the viewDidLoad methods of my left and right view for the SplitView. The breaks are being hit but nothing is displaying in my popover.
How can I display a UISplitView IN a PopoverController.
My Root View
- (IBAction)showPopover:(id)sender {
self.SVC = [[SplitViewContainerViewController alloc] init];
self.pickerPopover = [[[UIPopoverController alloc] initWithContentViewController:SVC] autorelease];
CGRect frame= CGRectMake(0,0, 0, 0);
[self.pickerPopover presentPopoverFromRect:frame inView:self.view permittedArrowDirections:0 animated:NO];
LoadView Of SplitViewContainerViewController
- (void)loadView
{
UIView *view=[[[UIView alloc]initWithFrame:CGRectMake(0, 0, 750, 880)]retain];
self.view=view;
self.splitViewController = [[UISplitViewController alloc] init];
self.leftViewController=[[[LeftViewController alloc] initWithStyle:UITableViewStylePlain] autorelease];
self.rightViewController=[[[RightViewController alloc] initWithStyle:UITableViewStylePlain] autorelease];
self.splitViewController.viewControllers= [NSArray arrayWithObjects:self.leftViewController, self.rightViewController, nil];
[self.view addSubview:self.splitViewController.view];
self.contentSizeForViewInPopover = CGSizeMake(750,880);
[super loadView];
}
UISplitViewControllers do not work unless they are the root view controller of the window. In order to do something like this you are going to need to create a custom split view controller and use that instead of UISplitViewController.
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. The panes of your split-view interface may then contain navigation controllers, tab bar controllers, or any other type of view controller you need to implement your interface.
You may want to start by looking at MGSplitViewController, however, be aware that there are some limitations in iOS 4 and below including the inability to correctly forward rotation and view appearance and disappearance events to the child view controllers.
Related
I created and loaded a UISplitViewController in an existing ViewController by writing the following code in the viewDidLoad method:
LeftPanelViewController *leftPanel = [[LeftPanelViewController alloc] initWithNibName:#"LeftPanelViewController" bundle:nil];
FirstViewController *firstView = [[FirstViewController alloc] initWithNibName:#"FirstViewController_iPad" bundle:nil];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:firstView];
UISplitViewController *splitController = [[UISplitViewController alloc] init];
splitController.viewControllers = [NSArray arrayWithObjects:leftPanel, self.navigationController, nil];
[self.view addSubview:splitController.view];
[self addChildViewController:splitController];
[splitController didMoveToParentViewController:self];
Everything is fine except for the fact that the splitController is not being drawn in the borders of the iPad, there's a space between the top of the screen and the top of the view. Even when I rotate the iPad the left panel is also having the same problem.
SplitViewController doesn't have a xib file, and when I change the added view for another that has, everything is correctly displayed.
Any ideas of what may cause this problem?
Notes:
Compiling and running the project in the simulator multiple times causes the SplitViewController to be displayed sometimes without any problems and others with spaces between any of the edges of the screen and the view. Running in the iPad causes always the same problem.
First of all.. why do you implement a container view controller? I guess you just want to present the splitViewController on its own, right? Than don't add the view yourself.
Instead correctly set it as your rootViewController on your window (preferably in applicationDidFinishLaunching).
self.window.rootViewController = splitViewController;
Container View Controller are not needed in standard cases. So you should never need to use the following methods:
addChildViewController:
removeFromParentViewController
willMoveToParentViewController:
didMoveToParentViewController:
Check the documentation of UIViewController.
If you really wanted to implement a Container View Controller, than you need to take care of the layout yourself. So you need to position / size the view of the other controller yourself. Depending on if you use AutoLayout or autoresizing, you need to set correct constraints/flags.
So in my universal app I have a section where a person can look at an existing list of notes from our system (retrieved through a simple web service) and then also create a new note if they want. So for the iphone it's pretty simple layout, a TableViewController for displaying the list with a "Add" button on the NavigationBar that presents the modalview for adding the new item. On the iPad though, the same layout has a lot of wasted space so I opted to go with the popOver method to show the list in a popOver and then let them add from there. My problem is that when the user clicks on the Add button within the PopOver view, the modal view comes up full screen instead of just coming up within the popover view. Here's the code I have so far:
-(void) AddButtonPressed:(id)sender {
NewNoteVC *newNote = [[[NewNoteVC alloc] initWithNibName:#"NewNoteVC" bundle:nil] autorelease];
newNote.defaultClientID = defaultClientID;
UINavigationController *navCon = [[[UINavigationController alloc] initWithRootViewController:newNote] autorelease];
if ([isPopOver isEqualToString:#"YES"]) {
[navCon setModalInPopover:YES];
[self.navigationController setModalInPopover:YES];
[self.navigationController presentModalViewController:navCon animated:YES];
}
else {
[self.navigationController presentModalViewController:navCon animated:YES];
}
}
The "isPopOver" string is just a placeholder sent from the previous screen that called this TableView (I know I can switch this to a boolean for better performance I just put this together real quick to try it out). I know I messed up somewhere, I just don't know what setting I need to get this working correctly.
You need to define the view controller's modalPresentationStyle to be "current context".
navCon.modalPresentationStyle = UIModalPresentationCurrentContext;
This will result in modal view controller filling the popover like the popover's root controller.
Try using the presentViewController:animated:completion: instead of presentModalViewController:animated: and set self.navigationController.definesPresentationContext = YES
I have an app for iPad with a UISplitViewController in it (UsersSplitViewController). On the left side (ROOT) of it I installed a UINavigationController (while the right side is used for a custom view).
The Navigation Controller has a hierarchy of 2 view controllers (2 different tableViews). As long as i push the second tableView on the stack (by selecting a row in the first tableview) everything works just fine: the animation consists in the second tableview sliding in from the right (default). However, when I touch the back button while the second controller is showed, instead of animating just the navigationController, the whole SplitViewController is animated (sliding in from the top of the screen!). Obviously, this is ugly, and just what i don't want... can anyone help?
This is where all the main controllers get instatiated (inside AppDelegate):
usersSplitViewController=[[UISplitViewController alloc] init];
usersRootViewController=[[UsersRootViewController alloc] initWithDataSource:self];
usersRootViewController.dataSource=self;
usersRootViewController.appDelegate=self;
usersDetailViewController=[[UsersDetailViewController alloc] init];
usersDetailViewController.dataSource=self;
usersDetailViewController.appDelegate=self;
usersDetailViewController.urvc=usersRootViewController;
usersRootViewController.usersDetailViewController=usersDetailViewController;
usersSplitViewController.viewControllers=[NSArray arrayWithObjects:usersRootViewController,usersDetailViewController,nil];
usersSplitViewController.delegate=usersDetailViewController;
[usersRootViewController release];
this is where, inside UsersRootViewController (subclass of UINavigationController), I instantiate the tableViews to be showed:
UITableViewController *userKindTableViewController=[[UITableViewController alloc] init];
//first tableView:
userKind=[[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStyleGrouped];
userKind.dataSource=self;
userKind.delegate=self;
userKindTableViewController.tableView=userKind;
userKindTableViewController.contentSizeForViewInPopover=CGSizeMake(320.0, 200.0);
[self pushViewController:userKindTableViewController animated:NO];
[userKindTableViewController release];
//second tableView:
usersOfKindTableViewController =[[UITableViewController alloc] init];
usersOfKind=[[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStylePlain];
usersOfKind.dataSource=self;
usersOfKind.delegate=self;
usersOfKindTableViewController.tableView=usersOfKind;
usersOfKindTableViewController.contentSizeForViewInPopover=CGSizeMake(320.0, 600.0);
finally, i Push the second TableView in the first one's "didSelectRowAtIndexPath":
[self pushViewController:usersOfKindTableViewController animated:YES];
Thanks
You need to overide the UITableViewController class and implement the
shouldAutorotateToInterfaceOrientation:
method so that it returns YES for
UIInterfaceOrientationLandscapeLeft and UIInterfaceOrientationLandscapeRight
orientations.Then use this class for your userKindTableViewController and usersOfKindTableViewController variables.
I'm trying to use a split view controller to show a navigation controller on the left and a table view on the right. I use this code in RootViewController's viewDidLoad:
self.clearsSelectionOnViewWillAppear = NO;
self.contentSizeForViewInPopover = CGSizeMake(320.0, 600.0);
Settings *settings = [[Settings alloc] init]; //Table view
MainView *main = [[MainView alloc] init]; //Table view
UINavigationController *nav_con = [[UINavigationController alloc] init];
NSArray *controllers = [[NSArray alloc] initWithObjects:settings, detailViewController, nil];
[nav_con pushViewController:settings animated:NO];
self.view = nav_con.view;
detailViewController.view = main.view;
I've tried like a million different ways of coding this, and this one comes the closest to correct. It displays the navigation controller in the left pane and the main view in the right. HOWEVER, in the left pane, at the top, there are two bars with a big black space between them. One of the bars in my nav controller's bar. How can I just replace the content of the left pane entirely with my navigation controller's view?
Settings and MainView better be subclasses of UITableViewController
the first object in controllers should be nav_con, not settings
delete the last two "view" lines,
and RootViewController should be a subclass of UISplitViewController and the instance that's being created should be set to window.rootViewController somewhere.
Also, it's fairly standard to do all this code external to viewDidLoad - makes me wonder what's being loaded as the view! Much easier to do all this in a nib file.
I have created a tab bar controller as follows:
tabBarController = [[UITabBarController alloc] init];
tabBarController.view.frame = CGRectMake(0, 0, 320, 460);
NSMutableArray *tabsArray = [[NSMutableArray alloc] init];
//tab1: dive info
LogsDetailDive *logsDetailDive = [[LogsDetailDive alloc] initWithNibName:#"LogsDetailDive" bundle:nil];
[logsDetailDive initWithLogSelected:logSelected:siteSelected];
logsDetailDive.title = #"Info";
logsDetailDive.tabBarItem.image = [UIImage imageNamed:#"/images/logs.png"];
[tabsArray addObject:logsDetailDive];
//tab2: deco info
...
//tab3: equipment info
...
//tab3: computer info
...
tabBarController.viewControllers = tabsArray;
[logsDetailDive release];
[self.view addSubview:tabBarController.view];
This tab controller is pushed from a previous table view into the navigation controller.
What I'm trying to get now is to show another view pushed from a tableview in LogsDetailDive, but I really cannot understand what I am missing, since it doesn't work.
Can you suggest something?
Thanks
UITabBarController reference
Because the UITabBarController class inherits from the UIViewController class, tab bar controllers have their own view that is accessible through the view property. When deploying a tab bar interface, you must install this view as the root of your window. Unlike other view controllers, a tab bar interface should never be installed as a child of another view controller.
So the bottom line, this should not be done, and will cause some problems. If you need a tabbar layout you should instead use a toolbar.