willHideViewController not called when switching to view in portrait mode - objective-c

My iPad app uses the standard UISplitViewController. My problem is, if I
Rotate to portrait, I put a Popover button for the Master list - Fine
Select an item via the popover, that changes the detailview (This uses a prepareForSegue which sets self.splitViewController.delegate = newViewDetailViewController;
The resulting detailview is now missing a popoverbutton. If I rotate to landscape, the master list appears. If I then again rotate to portrait, a popoverbutton appears.
So - How can I ensure willHideViewController will be called on viewDidLoad, for example?
I can detect what the orientation is, but I still need the barbuttonitem and popovercontroller needed in
- (void)splitViewController:(UISplitViewController *)splitController willHideViewController:(UIViewController *)viewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)popoverController
For now I am following Apples MultipleDetailView example as suggested here.
But since I am having multiple MasterControllers as well, it's a real hassle to store (a static) pointer to the popoverbutton item and setting it every time I push a level on my masterview controller.
Hopefully, someone has a good way of solving this problem :-)

I ran into the same problem and finally figured out what was missing. There is a little code in the AppDelegate to performs some initialization. It is in the didFinishLaunchingWithOptions method. Here is the code that goes in there:
UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
UINavigationController *navigationController = [splitViewController.viewControllers lastObject];
splitViewController.delegate = (id)navigationController.topViewController;
They're all important to operate the split view controller, but the last line is the most line for getting the method to fire is the last one. I am building a universal application and this was missing. To ensure that it didn't affect my iPhone side I wrapped it in a UI_USER_INTERFACE_IDIOM check.

Related

Unbalanced calls to begin/end appearance transitions for <UITableView> in iPad portrait

The iPad version of an app of mine uses a UISplitViewController on which I load UINavigationControllers on both view controllers. Upon some events both view controllers get new controllers pushed and popped. When I use the app in landscape everything works fine, while when I use it in portrait I get:
Unbalanced calls to begin/end appearance transitions for
iPuja.MonastersAndCentersTableViewController: 0x18d7b020.
notwithstanding everything seems to work fine, apart of the error.
That is how I pop the master controller from the detail one (Swift):
#IBAction func dismiss(sender: AnyObject) {
self.navigationController?.popViewControllerAnimated(true)
(self.splitViewController?.viewControllers[0] as? UINavigationController)?.popViewControllerAnimated(true)
}
and this how I push it (objective-c):
if([[[UIDevice currentDevice] model] isEqualToString:#"iPad"]){
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"StoryboardiPad" bundle: nil];
UIViewController *controller = [mainStoryboard instantiateViewControllerWithIdentifier: #"editCenters"];
[self.splitViewController.viewControllers[0] pushViewController:controller animated:YES];
}
If I skip popping the master controller I get no error, but of course the master detail is not popped up when I display it.
Funnily, if I briefly display the master controller in Portrait by dragging it, the error is not presented any longer, until I rotate it to landscape and rotate it again to portrait.
I managed the issue by delaying the operations on the master controller to when it is shown. The code is a little less elegant, but the warning is gone.

setStatusBarOrientation:animated: not working in iOS 6

I've used this code to force an orientation change back to portrait when the user is finished watching the video (it allows viewing in landscape mode), before popping the video view controller off the navigation controller:
//set statusbar to the desired rotation position
[[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationPortrait animated:NO];
//present/dismiss viewcontroller in order to activate rotating.
UIViewController *mVC = [[[UIViewController alloc] init] autorelease];
[self presentModalViewController:mVC animated:NO];
[self dismissModalViewControllerAnimated:NO];
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];
This worked perfectly until iOS 5.1.1. I've even tried to use the new present/dismiss methods after reading in another post that those should be used now:
[self presentViewController:mVC animated:NO completion:NULL];
[self dismissViewControllerAnimated:NO completion:NULL];
The problem is it doesn't work at all. After I rotated the video viewer to landscape and then pop it, my settings view (table view controller) comes back, but also in landscape mode.
I've even tried the tip from Here
"The setStatusBarOrientation:animated: method is not deprecated outright. However it now works only if the supportedInterfaceOrientations method of the topmost full screen view controller returns 0. This puts the responsibility of ensuring that the status bar orientation is consistent into the hands of the caller."
So I've experimented with setting a flag to force supportedInterfaceOrientations to return 0 (before calling the first code block above) but it doesn't work either.
Does anybody have a solution for this?
Thanks for your time and effort.
setStatusBarOrientation method has changed behaviour a bit. According to Apple documentation:
The setStatusBarOrientation:animated: method is not deprecated
outright. It now works only if the supportedInterfaceOrientations
method of the top-most full-screen view controller returns 0
Your root view controller should answer false to the method shouldAutorotate in order that your app responds to setStatusBarOrientation:animated
From Apple Documentation: "if your application has rotatable window content, however, you should not arbitrarily set status-bar orientation using this method"
To understand that, put a breakpoint in the shouldAutorotate method and you will see that it is called juste after setting the status bar orientation.
Here is how I fixed.
https://stackoverflow.com/a/14530123/1901733
The current question is linked with the question from the url above.
The statusBarOrientation is a real problem in ios6.

Hiding Master View Controller in SplitView regardless of device orientation

I've found lots of people asking for information on how to have the Master view displayed both in landscape and portrait orientation, but what I am trying to do is to having the right master view hidden regardless of the devices orientation and popping in from the side by using a navbar button.
What would help me enormously would be if someone could tell me where the logic for hiding the master view is located/executed when the device reorients. I've been looking at the template that comes with Xcode, Master/detail view for iOS, and I noticed these two following methods are declared in the AppDelegate.m file but I can't seem to find out where they are being executed from:
//Called when a button should be added to the nav bar for a view that is hidden
- (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;
}
All help would be appreciated.
You actually have no control over a UISplitViewController. The master view is always present in landscape view, and there is no possible way of changing this.
However, "Matt Gemmell created an excellent custom splitViewController called 'MGSplitViewController'. It is very easily implemented, heavily commented, and contains a lot of excellent features not found with a normal splitViewController (hide master view on landscape view, change placement of the split in landscape view, allow user to change size of split fluidly during runtime, etc)."
Info and demo: http://mattgemmell.com/2010/08/03/mgsplitviewcontroller-updated/
Straight to the source: https://github.com/mattgemmell/MGSplitViewController/
-=-=-=-=-=-=-=-=-=-=-=-
I've posted this before in a similar (but different) question with the same answer here:
How to hide master view in UiSplitviewcontroller in ipad
-=-=-=-=-=-=-=-=-=-=-=-
UPDATE:
In iOS 5.0 and beyond, they have finally added functionality to hide master view in landscape!
-(BOOL)splitViewController:(UISplitViewController *)svc shouldHideViewController:(UIViewController *)vc inOrientation:(UIInterfaceOrientation)orientation
{
return YES;
}
Reference:
splitViewController in Ipad that doesnt hide in portrait

UIModalPresentationFullScreen not working in iPad landscape mode?

I have added a ViewvController(B) as subview on ViewController(A). In ViewController A(SuperView) UIModelPresentationFullScreen working fine. But when am calling UIModelPresentationFull in ViewController B(SubView) it modelview showing in Portrait mode and that is also not fully viewed. How to solve this problem. Can any one help me please. I have tried 2 days.
This is what I tried in both the superview and subview...
picFBCapture *fbCapt = [[picFBCapture alloc] init];
//[self.navigationController pushViewController:fbCapt animated:YES];
//fbCapt.modalPresentationStyle = UIModalTransitionStyleFlipHorizontal;
fbCapt.modalTransitionStyle = UIModalPresentationFullScreen;
[self presentModalViewController:fbCapt animated:NO];
[fbCapt release];
Thanks in advance..
The problem is that if you add a view controller as a subview it's not connected to the view controller hierarchy and thus certain things doesn't work. You should avoid adding view controllers as subviews whenever possible, since this is not how Apple intend view controllers to be used, but sometimes it can't be avoided.
If this is one of those cases when it can't be avoided you should save a reference to view controller A in view controller B and then call presentModalViewController: on view controller A (that is connected to the view controller hierarchy) instead of self (view controller B, that isn't connected).
EDIT: In controller A you probably have code looking something like:
[self.view addSubview:controllerB.view];
In conjunction to this line add:
controllerB.controllerA = self;
I hope you know how to create properties, but if not here's a hint:
#property (nonatomic, assign) UIViewController *controllerA;
The rest you should be able to figure out using Google and the documentation.
You will have to handle viewController B's view in landscape by yourself. Since viewController B has been added as a subview, its view controller will not be handling its landscape orientation. The UIModalPresentationFullScreen style (landscape and portrait) will work only if viewController B is shown, ie not as subview but as a full view itself.

positioning problem with uisplitviewcontroller in left view

i got a little problem, when launching my splitview in landscape, there is a little black space above my left view controller:
after rotating my ipad to portrait and switching back to landscape, the space is gone.
if i load the uitableviewcontroller directly into the left view, and not in a navigationcontroller, it works fine:
any ideas why this is happening ??
// Produkte
self.produkteMainTableVC = [[produkteMainTableViewController alloc] initWithStyle:UITableViewStylePlain];
UINavigationController *produkteMainNavigationController = [[UINavigationController alloc] initWithRootViewController:self.produkteMainTableVC];
self.produkteDetailVC = [[produkteDetailViewController alloc] initWithNibName:#"produkteDetailViewController" bundle:nil];
self.produkteSplitVC = [[UISplitViewController alloc] init];
self.produkteSplitVC.delegate = self.produkteDetailVC;
self.produkteMainTableVC.produkteDetailVC = produkteDetailVC;
[self.produkteSplitVC setViewControllers:[NSArray arrayWithObjects:produkteMainNavigationController,self.produkteDetailVC,nil]];
thanks for all help!
edit:
its exactly 20px like the statusbar. does that help anyone?
edit2:
doing something like this:
if(self.navigationController.navigationBar.frame.origin.y >= 20.0) {
self.navigationController.navigationBar.frame = CGRectMake(self.navigationController.navigationBar.frame.origin.x, 0.0, self.navigationController.navigationBar.frame.size.width, self.navigationController.navigationBar.frame.size.height);
}
results that:
a little improvement i would say. but i have no idea how to stick my tableview underneath the navigationbar.
I know this is a very old topic but maybe it'll help other people...
I had the same issue (with the same configuration : splitview in tabbar).
This property solved it !
[self.splitViewController setWantsFullScreenLayout:YES];
UINavigationController has a nasty habit of shifting its contents down by 20px, depending where you place it. I'm guessing it's doing it here because your split view controller is inside of a tabbar controller, and Apple has not blessed this type of arrangement.
I've run into this same issue, with out a resolution. The only thing I've noticed is this does NOT happen when the master does not include a UINavigationController as its root.
Anyone figure a solution to this?
Here's what I did, and it seems to work fine.
I created my own custom tab-view controller, derived from UIViewController. In viewDidLoad I add a UITabBar to the bottom of the view and set the delegate to myself so I can handle tab changes. (I return this UITabBar as the rotatingFooterView) Tab changes result in swapping the current view controller, just like a real UITabBarController. When swapping view controllers (sometimes a UISplitViewController, hosting a UINavigationController in the master view), I add and position the view-controller's view within my view, above the UITabBar. I'm also careful to forward viewWill/DidAppear/Disappear calls to the current view controller, as well as each of the will/didRotate messages.
seems that this problem occurs from iOS 7.0. Setting the frame of UINavigationBar in some cases doesn't work. I think this can solve your problem :
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
self.navigationController.view.frame = CGRectMake(0, -20, self.navigationController.view.frame.size.width,
self.navigationController.view.frame.size.height);
}
This code should be called only once (for example in - (void)viewDidLoad ).
In my case it works for all device orientation.