SplitViewController Template show the popover manually? - ios

I am using the splitViewController template provided by Apple. On a specific action, I want to show the rootViewController. Unfortunately, I cannot find a method that will show the popover (programmatically) just as it does when you tap the bar button item.
Any Ideas? Thanks!

you can show the popover from a barButtonItem or with your own rect with these two methods:
[self.popoverController presentPopoverFromRect:(CGRect) inView:(UIView *) permittedArrowDirections:(UIPopoverArrowDirection) animated:(BOOL)];
[self.popoverController presentPopoverFromBarButtonItem:(UIBarButtonItem *) permittedArrowDirections:(UIPopoverArrowDirection) animated:(BOOL)]
self.popoverController is my case an ivar which stores the popover. I'm setting this variable each time in:
- splitViewController:willHideViewController:withBarButtonItem:forPopoverController:
and set it back to nil in it's counterpart method:
- splitViewController:willShowViewController:invalidatingBarButtonItem:
heres my code:
- (void)splitViewController: (UISplitViewController*)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem*)barButtonItem forPopoverController: (UIPopoverController*)pc {
barButtonItem.title = #"42";
self.navigationController.navigationBar.topItem.leftBarButtonItem = barButtonItem;
self.popoverController = pc;
}
- (void)splitViewController: (UISplitViewController*)svc willShowViewController:(UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem {
self.navigationController.navigationBar.topItem.leftBarButtonItem = nil;
self.popoverController = nil;
}

Related

iPad Split View Not Showing BarButtonItem When Switching View Controllers in Master View Controller

I am quite new to iPad Development, so please forgive my questions that might seem a little obvious.
I have an existing application for the iPhone which I am converting to a universal app for the iPad version.
The UI is going to be simple.
A Split View Controller where the Master represents a Static UITableView (Person, Timeline, Event, Date) for the user to select. The Detail will of course display whichever cell was selected in the UITableView Master. Both the Detail and Master have been created in Storyboard and are both NavigationControllers.
I am trying to do the common aspect of: Landscape mode shows both the Master and Detail View, while Portrait shows only the Detail View, but with a UIBarButtonItem that pops out the Master when requested.
Issue
When I rotate from Landscape to Portrait, the UIBarButtonItem is visible and I can press it to bring out the Master View in Portrait mode.
In portrait mode, if I bring out the button and select a different cell from the Master View, when I dismiss the Master by tapping anywhere in the Detail View, it doesn't now show the UIBarButton.
I am following http://www.dharmaworks.net/Consulting/switching-detail-views-in-uisplitviewcontroller-with-ios7/ as a way to get try get this working.
Code
MasterTableView:
#pragma mark - Split View Delegate
- (void)splitViewController:(UISplitViewController *)splitController willHideViewController:(UIViewController *)viewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)popoverController
{
UINavigationController *navController = [[[self splitViewController ] viewControllers ] lastObject ];
id vc = [[navController viewControllers] firstObject];
[vc setSplitViewButton:barButtonItem forPopoverController:popoverController];
}
- (void)splitViewController:(UISplitViewController *)splitController willShowViewController:(UIViewController *)viewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem
{
UINavigationController *navController = [[[self splitViewController ] viewControllers ] lastObject ];
id vc = [[navController viewControllers] firstObject];
[vc setSplitViewButton:nil forPopoverController:nil];
}
SplitViewPresenter Protocol
#property (nonatomic, strong) UIBarButtonItem *splitViewBarButtonItem;
-(void)setSplitViewButton:(UIBarButtonItem *)splitViewButton forPopoverController:(UIPopoverController *)popoverController;
Detail View
-(void) turnSplitViewButtonOn: (UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *) popoverController {
barButtonItem.title = NSLocalizedString(#"Master", #"Master");
_splitViewBarButtonItem = barButtonItem;
[self.navigationItem setLeftBarButtonItem:barButtonItem animated:YES];
self.masterPopoverController = (MasterTableViewController *)popoverController;
}
-(void)turnSplitViewButtonOff
{
NSLog(#"SplitViewButtonOff Called");
// Called when the view is shown again in the split view, invalidating the button and popover controller.
[self.navigationItem setLeftBarButtonItem:nil animated:YES];
_splitViewBarButtonItem = nil;
self.masterPopoverController = nil;
}
-(void) setSplitViewButton:(UIBarButtonItem *)splitViewButton forPopoverController:(UIPopoverController *)popoverController
{
NSLog(#"Split View Being Called");
if (splitViewButton != _splitViewBarButtonItem) {
if (splitViewButton) {
NSLog(#"Split View Button Being Called");
[self turnSplitViewButtonOn:splitViewButton forPopoverController:popoverController];
} else {
[self turnSplitViewButtonOff];
NSLog(#"Split View Button Not Being Called");
}
}
}
The .h file of the Detail View is declared to use the SplitViewPresenter.
Update
I understand why this is occurring. The setter is only getting called when I rotate from the Landscape to Portrait mode. My question is, how do I get this to work without the rotation? Also, within the link above that I have followed, I have not implemented any of the didSelectRow code. Should I be doing that?
Any guidance on this would really be appreciated.

Turn of parallax for UIPopoverController

In iOS 7 UIPopoverControllers have the parallax effect (foreground hovering over background).
This is especially ugly in a UISplitViewController that is in portrait mode.
Lines are not on the same level. No matter how you hold it, initially the popover is 4-5 pixels above where it should be
There are no separators (not even hairlines) on top / at the bottom of the popover. This results in the popover looking even more missplaced.
Has anyone found a good workaround/fix for this?
Edit:
Edit 2:
UIActionSheet also has this parallax effect.
Edit 3:
My delegate method that is somehow related to the presentation of the master
- (void)splitViewController:(UISplitViewController *)splitController willHideViewController:(UIViewController *)viewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)popoverController
{
barButtonItem.title = NSLocalizedString(#"Übersicht", nil);
[self.navigationItem setLeftBarButtonItem:barButtonItem animated:YES];
self.masterPopoverController = popoverController;
}
A little bit hacky, but works for UISplitViewController:
- (void)splitViewController:(UISplitViewController *)svc popoverController:(UIPopoverController *)pc willPresentViewController:(UIViewController *)aViewController
{
UIView *popoverView = [[aViewController.view superview] superview];
popoverView.motionEffects = #[];
}

Popover not displaying correctly

I'm following a demo about hiding the left side of a Split View when the iPad is in Portrait, and then showing it as a Popover when a button placed in a toolbar is pressed. I followed everything step-by-step and it works (sort of) except that when I press the button, instead of in a Popover the view is displayed sliding from left to right. I also noticed that I can get the same result by sliding my finger from left to right instead of pressing the button.
This is the code I use (same code works properly in the demo).
in the View Controller of the view that should be shown in the Popover:
-(BOOL)splitViewController:(UISplitViewController*)svc
shouldHideViewController:(UIViewController*)vc
inOrientation:(UIInterfaceOrientation)orientation
{
return [self splitViewBarButtonItemPresenter] ? UIInterfaceOrientationIsPortrait(orientation) : NO;
}
-(void)splitViewController:(UISplitViewController *)svc
willHideViewController:(UIViewController *)aViewController
withBarButtonItem:(UIBarButtonItem *)barButtonItem
forPopoverController:(UIPopoverController *)pc
{
barButtonItem.title = self.title;
[self splitViewBarButtonItemPresenter].splitViewBarButtonItem = barButtonItem;
}
-(void)splitViewController:(UISplitViewController *)svc
willShowViewController:(UIViewController *)aViewController
invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem
{
[self splitViewBarButtonItemPresenter].splitViewBarButtonItem = nil;
}
And in the View that should display the Popover:
-(void)setSplitViewBarButtonItem:(UIBarButtonItem *)splitViewBarButtonItem
{
if (_splitViewBarButtonItem != splitViewBarButtonItem){
NSMutableArray *toolbarItems = [self.toolbar.items mutableCopy];
if (_splitViewBarButtonItem) [toolbarItems removeObject:_splitViewBarButtonItem];
if (splitViewBarButtonItem) [toolbarItems insertObject:splitViewBarButtonItem atIndex:0];
self.toolbar.items = toolbarItems;
_splitViewBarButtonItem = splitViewBarButtonItem;
}
}
SplitViewBarButtonItemPresenter is just a protocol used to delegate who should show (you guessed it!) the button for the popover.

iPad SplitViewController Show Popover programmatically

I have an iPad SplitViewController application in which I hide the left pane in both portrait and landscape modes. I need to show the left pane in its popover when a certain notification is received by the application. Despite experimenting with a number of different suggested solutions I am struggling to work out how to achieve this.
I am using a MultipleMasterDetailManager implementation that includes the following code:
/* forward the message to the current detail view
* all detail views must implement UISplitViewControllerDelegate
*/
-(void)splitViewController:(UISplitViewController *)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)pc
{
self.masterBarButtonItem = barButtonItem;
self.masterPopoverController = pc;
barButtonItem.title = NSLocalizedString(#"Show Sidebar", #"Show Sidebar");
[self.currentDetailController.navigationItem setLeftBarButtonItem:self.masterBarButtonItem animated:YES];
}
/* forward the message to the current detail view
* all detail views must implement UISplitViewControllerDelegate
*/
-(void)splitViewController:(UISplitViewController *)svc willShowViewController:(UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem
{
//if (![self.currentDetailController isKindOfClass:[SyncSourceDetailViewController class]])
//{
self.masterBarButtonItem = nil;
self.masterPopoverController = nil;
[self.currentDetailController.navigationItem setLeftBarButtonItem:nil animated:YES];
//}
}
Similar methods exist in the detail view controllers themselves.
The method that I'm calling when the notification is received is as follows:
- (void)navigateToLatest
{
[self navigateToDocumentsTab];
[[self dataLoader] navigateToLatest]; // populates data for the left table view
UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
UIView *view = [[[[[splitViewController viewControllers] objectAtIndex:1] viewControllers] objectAtIndex:0] view];
[self.masterDetailManager.masterPopoverController presentPopoverFromRect:CGRectMake(0, 0, 100, 100) inView:view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
This does not work. I've also tried using the presentPopoverFromBarButtonItem method but I cannot seem to locate the leftBarButtonItem in code.
Maybe I am going about this completely the wrong way.
I ended up solving this problem by setting a "showSidebar" variable in my app delegate to true in the navigateToLatest method. Then in my DetailViewController's ViewDidAppear event I check the value of this variable, if it is true then I show the sidebar using the following code:
UIPopoverController *masterPopoverController= [[theAppDelegate masterDetailManager] masterPopoverController];
[masterPopoverController presentPopoverFromBarButtonItem:[self.navigationItem leftBarButtonItem] permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
[theAppDelegate setShowSidebar:NO];

UISplitViewController iOS 5.1 causes popover arrow direction error

My app was working perfectly prior to iOS 5.1. It is a UISplitviewController with a UINavigationController in the left-hand pane, and updates the detail pane dependent upon choices made within that UINavigationController.
The new sliding-in from left replacement for the popover, endemic to iOS 5.1 works; it doesn't look great, but it works.
What appears to be broken is the display of the 'popover' from the bar button in portrait. It causes an exception - 'NSInternalInconsistencyException', reason: 'Unknown direction passed to _popoverViewSizeForContentSize:arrowDirection:'
I have tried to override the method which displays the popover as follows:
-(void)splitViewController:(UISplitViewController *)svc popoverController:(UIPopoverController *)pc willPresentViewController:(UIViewController *)aViewController
{
[self.popoverController presentPopoverFromBarButtonItem:self.masterPopoverButtonItem permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
But I still get the same error. Can anyone help?
Use the below delegates to display the master page from details page
- (void)splitViewController:(UISplitViewController *)splitController willHideViewController:
(UIViewController *)viewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)popoverController
{
barButtonItem.title = NSLocalizedString(#"Master", #"Master");
[self.navigationItem setLeftBarButtonItem:barButtonItem animated:YES];
self.masterPopoverController = popoverController;
}
- (void)splitViewController:(UISplitViewController *)splitController willShowViewController:(UIViewController *)viewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem
{
// Called when the view is shown again in the split view, invalidating the button and popover controller.
[self.navigationItem setLeftBarButtonItem:nil animated:YES];
self.masterPopoverController = nil;
}

Resources