In my iPad App I'm using a UISplitViewController with two UINavigationControllers as master and detail. In Potrait I'd like the master to be hidden and accessible via UIPopoverViewController. This is the implementation of my UISplitViewController subclass, which works fine:
- (id)init {
self = [super init];
if (self) {
_splitViewController = [[UISplitViewController alloc] init];
_splitViewController.delegate = self;
_searchViewController = [[UIViewController alloc] init];
_searchViewController.view.backgroundColor = [UIColor whiteColor];
_masterNavController = [[UINavigationController alloc] initWithRootViewController:_searchViewController];
_masterNavController.navigationBar.translucent = NO;
_mapViewController = [[MapViewController_iPad alloc] init];
_detailNavController = [[UINavigationController alloc] initWithRootViewController:_mapViewController];
_detailNavController.navigationBar.translucent = NO;
_splitViewController.viewControllers = #[_masterNavController, _detailNavController];
_splitViewController.view.backgroundColor = [UIColor redColor];
}
return self;
}
#pragma mark -
#pragma mark - UISplitViewControllerDelegate
- (void)splitViewController:(UISplitViewController *)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)pc {
svc.view.backgroundColor = [UIColor redColor];
barButtonItem.title = NSLocalizedString(#"ipad_search_vc_bar_button_title", #"Name of the master view controller button on iPad");
[self.mapViewController.navigationItem setLeftBarButtonItem:barButtonItem animated:YES];
}
- (void)splitViewController:(UISplitViewController *)svc willShowViewController:(UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem {
svc.view.backgroundColor = [UIColor redColor];
[self.mapViewController.navigationItem setLeftBarButtonItem:nil animated:YES];
}
- (void)splitViewController:(UISplitViewController *)svc popoverController:(UIPopoverController *)pc willPresentViewController:(UIViewController *)aViewController {
svc.view.backgroundColor = [UIColor redColor];
[pc setPopoverBackgroundViewClass:[CustomPopoverBackgroundView class]];
}
This is how it looks:
After starting the App the first time and tapping the UIBarButton, the master looks like the following:
After hiding and tapping the UIBarButton item the second time, the master looks like it's supposed to. It has the red divider line instead of the standard colored one:
Now, the CustomBackgroundView that is used in the UISplitViewController delegate is actually being instantiated, but somehow not used the first time around.
Any idea how I could force the UIPopOverController to use the CustomBackgroundView the first time?
I ended up simply adding a subview to the UISplitViewController's view, which has the same color as the UINavigationBar.
UISplitViewController *splitViewController = [[UISplitViewController alloc] init];
[splitViewController.view addSubview:coloredView];
Is your Split View your root view controller? It looks like you have your split view within a Navigation Controller, which is not allowed. That would explain your graphical bugs.
Related
I would like to use an MPMediaPickerController in a navigation controller.
This does work:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MusicImport" bundle:[NSBundle mainBundle]];
UINavigationController *nav = [storyboard instantiateInitialViewController];
self.picker = [[MPMediaPickerController alloc] initWithMediaTypes:MPMediaTypeAnyAudio];
self.picker.delegate = self;
self.picker.allowsPickingMultipleItems = NO;
self.picker.showsCloudItems = NO;
self.picker.view.frame = CGRectMake(0, 0, 1024, 768);
// add to dummy VC's view
[[nav.viewControllers[0] view] addSubview:self.picker.view];
nav.navigationBarHidden = YES;
nav.delegate = self;
self.mainNav = nav;
I then push my custom view controller when the user selects an item in the picker:
self.selectedItem = mediaItemCollection.items[0];
self.playbackViewController = [[PlaybackViewController alloc] initWithNibName:#"PlaybackViewController" bundle:[NSBundle mainBundle]];
self.playbackViewController.mediaItem = self.selectedItem;
self.playbackViewController.delegate = self;
self.mainNav.navigationBar.tintColor = self.picker.navigationController.navigationBar.tintColor;
self.mainNav.navigationBarHidden = NO;
[self.mainNav pushViewController:self.playbackViewController animated:YES];
so far, so good. only problem here is that the tintColor thing does not work.
the real problem is that when navigating back from my custom playback VC, the media picker does not become visible.
Even when I'm trying to add it back in the navigation controller's delegate method:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if(viewController == navigationController.viewControllers[0])
{
[viewController.view addSubview:self.picker.view];
navigationController.navigationBarHidden = YES;
}
}
alas, no dice.
I am trying to add a button to my navigation bar on my detail view to show the master view when in portrait mode but the button isn't showing up. Can anyone help or offer suggestions?
Here is how I was trying to do it in the detail view:
- (void)splitViewController:(UISplitViewController *)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)pc
{
mainMenu = barButtonItem;
[mainMenu setTitle:#"Menu"];
[[self navigationItem]setLeftBarButtonItem:mainMenu];
}
- (void)splitViewController:(UISplitViewController *)svc willShowViewController:(UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem
{
if (mainMenu == [[self navigationItem]leftBarButtonItem])
{
[[self navigationItem]setLeftBarButtonItem:nil];
}
}
Here is how I'm loading the detail view when selecting a row in my master view:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSMutableArray *details = [self.splitViewController.viewControllers mutableCopy];
UINavigationController *detailNav = [[UINavigationController alloc]initWithRootViewController:webViewController];
[details replaceObjectAtIndex:1 withObject:detailNav];
self.splitViewController.viewControllers = details;
KFBAppDelegate *appDelegate = (KFBAppDelegate *)[[UIApplication sharedApplication]delegate];
appDelegate.window.rootViewController = self.splitViewController;
I've added this to viewDidLoad and the button shows up now but I'm not sure how to get it to show the master view.
mainMenu = [[UIBarButtonItem alloc]init];
[mainMenu setTitle:#"Menu"];
self.navigationItem.leftBarButtonItem = mainMenu;
Here is a picture of what it looks like when I swipe from the left to show the master view.
I've managed to get a left button to appear but now I don't know how to have it open the master view. Here is how I got the button to show up:
mainMenu = [[UIBarButtonItem alloc]init];
[mainMenu setTitle:#"Menu"];
self.navigationItem.leftBarButtonItem = mainMenu;
Rather than left button, use right bar button and it will show. The problem is the button on the left gets hidden by the default button of the vavigation controller. Try the right bar button.
Edit
This is a generic method that is placed in view did load to include a right bar button. then you can access is in other methods. hope it helps.
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(insertNewObject:)];
self.navigationItem.rightBarButtonItem = addButton;
self.detailViewController = (DetailViewController *)[[self.splitViewController.viewControllers lastObject] topViewController];
In here insert new object in the selector is the IBAction that you use to declare what that button has to do.
I have a searchcontrollerviewcontroller, detailviewcontroller and a filterviewcontroller
In Appdelegate I added the first 2 as splitview controller and delegate to detailviewcontroller like this:
self.splitViewController.delegate = detailViewController;
self.splitViewController.viewControllers = [NSArray arrayWithObjects:searchViewController, detailNavigationController, nil];
when the ipad turns it shows buttons for the popoverview
- (void)splitViewController:(UISplitViewController *)splitController
willHideViewController:(UIViewController *)viewController
withBarButtonItem:(UIBarButtonItem *)barButtonItem
forPopoverController:(UIPopoverController *)popoverController{
UIBarButtonItem *filterbutton = [[UIBarButtonItem alloc]initWithTitle:#"Filter" style:UIBarButtonItemStylePlain target:nil action:#selector(showFilterPopover:)];
barButtonItem.title = NSLocalizedString(#"Search", #"Search results");
[self.navigationItem setLeftBarButtonItems:[NSArray arrayWithObjects:barButtonItem,filterbutton, nil] animated:YES];
self.masterPopoverController = popoverController;
}
I init the filterview in here
-(void)showFilterPopover: (id) sender{
FilterViewController *controller = [[FilterViewController alloc]initWithNibName:#"FilterViewController" bundle:nil];
UIPopoverController *popover =
[[UIPopoverController alloc] initWithContentViewController:controller];
popover.delegate = self;
self.masterPopoverController = popover;
[self.masterPopoverController
presentPopoverFromBarButtonItem:sender
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
}
But nothing happens, the popover works for the detailview but not for the filterview....
Am I forgetting something ?
I'm trying to hide the master view in UISplitView in the landscape mode. This i want to do on an button click. In my navigation bar I have a button on click of which I want to hide the master view in landscape mode. Also if the master view is hidden then on click of that same button it should show the master view back. All this needs to be done in master view. I referred to the following function
-(BOOL)splitViewController:(UISplitViewController *)svc shouldHideViewController:(UIViewController *)vc inOrientation:(UIInterfaceOrientation)orientation
{
return YES;
}
But it hides master view on view load in spite of button click. Below is my code for detail view
- (void)setDetailItem:(id)newDetailItem {
if (detailItem != newDetailItem) {
[detailItem release];
detailItem = [newDetailItem retain];
// Update the view.
NSLog(#"Detail item in detail view::%#",detailItem);
NSString *imageName = [NSString stringWithFormat:#"%#.jpg",[detailItem description]];
NSLog(#"Image name is::%#",imageName);
self.imageToDisplay.image = [UIImage imageNamed:imageName];
[self configureView];
}
if (mainpopover != nil) {
[mainpopover dismissPopoverAnimated:YES];
}
}
- (void)configureView
{
// Update the user interface for the detail item.
detailDescriptionLabel.text = [detailItem description];
openInButton = [[UIBarButtonItem alloc] initWithTitle:#"OpenIn" style:UIBarButtonItemStyleDone target:self action:#selector(openIn)];
favoritesButton = [[UIBarButtonItem alloc] initWithTitle:#"*" style:UIBarButtonItemStyleDone target:self action:#selector(markFavorite)];
emailButton = [[UIBarButtonItem alloc] initWithTitle:#"E" style:UIBarButtonItemStyleDone target:self action:#selector(emailFile)];
uploadButton = [[UIBarButtonItem alloc] initWithTitle:#"#" style:UIBarButtonItemStyleDone target:self action:#selector(uploadFile)];
self.navigationItem.rightBarButtonItems = [NSArray arrayWithObjects:openInButton, favoritesButton,emailButton, uploadButton, nil];
}
#pragma mark -
#pragma mark Split view support
-(void)splitViewController:(UISplitViewController *)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)pc
{
barButtonItem.title = #"Quicksync";
self.navigationItem.leftBarButtonItem = barButtonItem;
self.mainpopover = pc;
}
// Called when the view is shown again in the split view, invalidating the button and popover controller.
-(void)splitViewController:(UISplitViewController *)svc willShowViewController:(UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem
{
myBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"<" style:UIBarButtonItemStyleDone target:self action:#selector(hideMasterScreen)];
self.navigationItem.leftBarButtonItem = myBarButtonItem;
self.mainpopover = nil;
}
// Called when the hidden view controller is about to be displayed in a popover.
- (void)splitViewController:(UISplitViewController*)svc popoverController:(UIPopoverController*)pc willPresentViewController:(UIViewController *)aViewController
{
// Check to see if the popover presented from the "Tap" UIBarButtonItem is visible.
if ([barButtonItemPopover isPopoverVisible]) {
// Dismiss the popover.
[barButtonItemPopover dismissPopoverAnimated:YES];
}
}
-(BOOL)splitViewController:(UISplitViewController *)svc shouldHideViewController:(UIViewController *)vc inOrientation:(UIInterfaceOrientation)orientation
{
return YES;
}
I get an orientation problem while using the following to code to display a view on top of a split view.
[window addSubview:aSplitViewController.view];
[window insertSubview:aViewController.view aboveSubview:aSplitViewController.view];
the plain view has a couple of buttons and labels.
So the problem I am facing is that the first view opens in landscape mode but the labels and buttons on the view are in portrait mode.
UPDATE: Here is some code so if anyone wants to see more details...
In my App Delegate
- (void) makeSplitViewController {
NSMutableArray *controllers = [NSMutableArray arrayWithArray:tabBarController.viewControllers];
// First tabbbar item
// detail view
detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailView" bundle:nil];
UINavigationController *navDetailView = [[[UINavigationController alloc] initWithRootViewController:detailViewController] autorelease];
navDetailView.hidesBottomBarWhenPushed = YES;
// root view
rootViewController = [[RootViewController alloc] initWithStyle:UITableViewStylePlain];
rootViewController.detailViewController = detailViewController;
rootViewController.navigationItem.title = #"List";
UINavigationController *navRootView = [[[UINavigationController alloc] initWithRootViewController:rootViewController] autorelease];
navRootView.hidesBottomBarWhenPushed = YES;
navRootView.navigationBar.barStyle = UIBarStyleBlackTranslucent;
splitViewController = [[UISplitViewController alloc] init];
splitViewController.tabBarItem.title = #"Face Sheet";
splitViewController.tabBarItem.image = [UIImage imageNamed:#"gear1.png"];
splitViewController.navigationItem.title = #"Face Sheet";
splitViewController.viewControllers = [NSArray arrayWithObjects:navRootView, navDetailView, nil];
splitViewController.delegate = detailViewController;
splitViewController.hidesBottomBarWhenPushed = YES;
[controllers addObject:splitViewController];
// Second tabbbar item
scoreViewController = [[ScoreCardViewController alloc] initWithNibName:#"TableViewController" bundle:nil];
scoreViewController.tabBarItem.title = #"Score Card";
scoreViewController.tabBarItem.image = [UIImage imageNamed:#"gear1.png"];
scoreViewController.navigationItem.title = #"Score Card";
[controllers addObject:scoreViewController];
tabBarController.viewControllers = controllers;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Create tabbar
tabBarController = [[UITabBarController alloc] init];
//tabBarController.delegate = self;
// Set window
[window addSubview:splashController.view];
[window insertSubview:tabBarController.view belowSubview:splashController.view];
[self.window makeKeyAndVisible];
application.statusBarOrientation = UIInterfaceOrientationLandscapeRight;
return YES;
}
and here is the code in my SplashScreenView
- (IBAction) proceedButtonClick:(id)sender
{
// Initialize loginpopview
PhysicianLoginViewController *loginViewController = [[PhysicianLoginViewController alloc] init];
popOverController = [[UIPopoverController alloc] initWithContentViewController:loginViewController];
popOverController.popoverContentSize = CGSizeMake(350, 200);
popOverController.delegate = self;
// Set a notification to dismiss it later
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(loginViewControllerDone:) name:#"loginViewControllerDone" object:popOverController.contentViewController];
// Present popover
if ([popOverController isPopoverVisible])
{
[popOverController dismissPopoverAnimated:YES];
}
else
{
[popOverController presentPopoverFromRect:CGRectMake(485, 600, 100, 100) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionDown animated:YES];
}
}
// Dismiss popview controller and setup the tabbar
- (void)loginViewControllerDone:(NSNotification *)notification{
[[NSNotificationCenter defaultCenter] removeObserver:self];
// Button in content view controller was tapped, dismiss popover...
[self.popOverController dismissPopoverAnimated:YES];
// remove subview
[self.view removeFromSuperview];
// set tabbar
i3EAppDelegate *appDelegate = (i3EAppDelegate *) [[UIApplication sharedApplication]delegate];
[appDelegate makeSplitViewController];
}
It would be great if someone could point out where I am going wrong. I have been stuck with this problem for quite a few days and I have tried everything that comes to my mind...
UIWindow has a subview that it uses for rotations and puts other views inside of that. You need to insert yourself into the root view (or something lower), not the window. Look at -[UIWindow rootViewController].
UIView *rootView = [[[self window] rootViewController] view];
[rootView addSubview:view];
This will work as long as you're using something with a root view controller. This will work as long as rootViewController isn't nil. If you're doing a raw "View Based" application, then it's usually best to pick another view and add your view as its sibling rather than digging through the undocumented hierarchy:
UIView *sibling = ... (some other view)
[[sibling superview] addSubview:view];