In iOS 8.3, I present a view controller with the following code:
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:controller];
nav.modalPresentationStyle = UIModalPresentationFormSheet;
nav.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentViewController:nav animated:YES completion:nil];
Upon presentation in my iPad simulator, I check the UITraitCollection property of my view (po self.traitCollection) in the viewDidLoad() method and here is what I get:
<_UITraitNameHorizontalSizeClass = Regular,
_UITraitNameVerticalSizeClass = Regular>
I switch the simulator from iPad to iPhone (5s or 6) and I still get the Regular horizontal size class trait in my view. iPhones should have an Compact horizontal size class trait.
Since the horizontal size class is wrong, the wrong size class design is loaded from the storyboard. Any ideas why the framework is providing a wrong size class?
Related
When presenting a view controller, I would like it to take 100% of the screen width/height on iPhone portrate mode, but take part of the screen in landscape (like this):
And to be partial on iPad. The following code does everything except the partial on iPhone landscape:
SQLProEditConnetionViewController * editConnectionViewController =
[[SQLProEditConnetionViewController alloc] initWithConnectionModel: nil];
editConnectionViewController.delegate = self;
UINavigationController * navController =
[[UINavigationController alloc] initWithRootViewController: editConnectionViewController];
navController.modalPresentationStyle = UIModalPresentationFormSheet;
navController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
navController.preferredContentSize = CGSizeMake(320, 620); // size of popup view
[self presentViewController: navController
animated: YES
completion: nil];
Any ideas how I can properly get this to work for iPhone landscape mode?
Change this: modalPresentationStyle in your code.
navController.modalPresentationStyle = UIModalPresentationFullScreen;
Hope this will work...!!
On iPhone and iPod touch, the presented view is always full screen. On iPad, the presentation depends on the value in the modalPresentationStyle property.
It turns out that I was seeing this due to the iPhone SE simulator. On larger devices it works how I want it.
How can you present a UIViewController in a popover on iPhone (all sizes and orientations), in iOS 8 using only Objective-C code, no Story Boards or other Interface Builder artifacts.
In iOS 8, you can configure any view controller to be displayed as a popover, like so:
UIViewController* controller = ...; // your initialization goes here
// set modal presentation style to popover on your view controller
// must be done before you reference controller.popoverPresentationController
controller.modalPresentationStyle = UIModalPresentationPopover;
controller.preferredContentSize = CGSizeMake(150, 300);
// configure popover style & delegate
UIPopoverPresentationController *popover = controller.popoverPresentationController;
popover.delegate = controller;
popover.sourceView = sourceView;
popover.sourceRect = CGRectMake(150,300,1,1);
popover.permittedArrowDirections = UIPopoverArrowDirectionAny;
// display the controller in the usual way
[self presentViewController:controller animated:YES completion:nil];
So that it displays as a popover on iPhone, add this to the UIPopoverPresentationControllerDelegate delegate of the popover (that you set above):
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller
{
return UIModalPresentationNone;
}
I've got a universal app that supports both iPad and iPhone, and on the iPhone it supports UIInterfaceOrientationPortraitUpsideDown.
When I run the app on an iPhone, then rotate the device to UIInterfaceOrientationPortraitUpsideDown, then modally present a view controller like this:
UIViewController* vc = [[UIViewController alloc] initWithNibName:nil bundle:nil];
UINavigationController* navigationController = [[UINavigationController alloc]
initWithRootViewController:vc];
navigationController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentViewController:navigationController animated:YES completion:nil];
Very unexpectedly, this triggers UIApplicationDidChangeStatusBarOrientationNotification.
OK, so maybe this is because the modal view controller does not support the upside-down portrait orientation. Let's make a custom subclass of UIViewController that overrides supportedInterfaceOrientations:
- (NSUInteger) supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
But no difference, presenting the custom VC still triggers the notification. I also noticed that the notifications is not triggered on iPad, only on iPhone. Finally, the behaviour is the same in iOS 8 and iOS 7 (specifically I am testing on iOS 8.1 and iOS 7.1, but I doubt that this makes any difference).
Question: Is it normal that this notification is sent when a modal VC is presented? Why does it happen only for UIInterfaceOrientationPortraitUpsideDown, but not for the regular portrait or any of the two landscape orientations? And why does it happen only on iPhone, not on iPad?
Note: I can provide a more complete, minimal running example on request.
The problem was, indeed, that the modally presented view controller did not support UIInterfaceOrientationPortraitUpsideDown. My idea to add an override of supportedInterfaceOrientations was correct, but where I went wrong was that I added the override to the custom subclass of UIViewController - but this is not the presented view controller!
The presented view controller, as my code snippet shows, is the UINavigationController instance. One correct solution to my problem therefore is to create a subclass of UINavigationController and add supportedInterfaceOrientations to that subclass.
Another correct, but in my case more elegant solution than subclassing is to make use of the UINavigationControllerDelegate protocol.
Step 1: Modify the code snippet from my question:
UIViewController* vc = [[UIViewController alloc] initWithNibName:nil bundle:nil];
UINavigationController* navigationController = [[UINavigationController alloc]
initWithRootViewController:vc];
navigationController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
// --- THE NEXT LINE IS NEW ---
navigationController.delegate = self;
[self presentViewController:navigationController animated:YES completion:nil];
Step 2: Make sure that the class that contains the presenting code (= the above code snippet) adopts the UINavigationControllerDelegate protocol.
Step 3 (yes, there is a step 3): Add this protocol method to the newly designated delegate class:
- (NSUInteger) navigationControllerSupportedInterfaceOrientations:(UINavigationController*)navigationController
{
return UIInterfaceOrientationMaskAll;
}
If you have many places where you present view controllers you will probably want to have some shared object that adopts UINavigationControllerDelegate, but that's part of your application design.
I am working on universal iPhone/iPad application with universal storyboard. For some ViewControllers I'm using size classes if they has some specific layout on iPad.
I have one ViewController that needs to be presented modally on iPhone but on iPad it needs to be shown in UIPopoverController.
UINavigationController *navigationController = [self.storyboard instantiateViewControllerWithIdentifier:#"ComposeMessageNavigationController"];
ComposeMessageViewController *viewController = (ComposeMessageViewController *)navigationController.topViewController;
//Prepeare my view controlller
...
if (IS_IPAD) {
UIPopoverController * popover = [[UIPopoverController alloc] initWithContentViewController:navigationController];
CGSize screenSize = [UIScreen mainScreen].bounds.size;
CGRect popoverFrame = CGRectMake(screenSize.width / 2, screenSize.height / 2, 1, 1);
[popover presentPopoverFromRect:popoverFrame inView:self.view permittedArrowDirections:0 animated:YES];
} else {
[self presentViewController:navigationController animated:YES completion:^{
}];
}
It works pretty good but there is problem with Size Classes. I made some changes on storyboard at wRegular/hRegular Size Class but on iPad in UIPopoverController still showing iPhone layout. It's because of size of popover is lower then iPad screen. Can I make my changes in Interface Builder with Size Classes to show them in popover on iPad but ignore on iPhone?
Using setOverrideTraitCollection on the popover view controller should allow you to use the regular x regular for an iPad.
I just ran into a very frustrating problem. I don't know if it's an iOS8 bug or it's something else.
I'm loading the view from a nib, which looks like this:
Here ist my code:
UIViewController *popoverViewController = [[UIViewController alloc] init];
[popoverViewController setView:poppverViewFromNib];
_popoverController = [[UIPopoverController alloc] initWithContentViewController:popoverViewController];
[_popverController presentPopoverFromRect:CGRectMake(100, 100, 10, 10) inView:[self view] permittedArrowDirections:UIPopverArrowDirectionAny animated:YES];
The iOS simulator as well as the real device are displaying the viewController modally like you can see here:
EDIT
As requested in comments, I tell you what I expect when using UIPopoverController:
I expect an UIPopover, not a modalViewController.
So here my question to all of those how didn't get it: Why does my UIPopoverController does not display as a popover but as modalViewController? How can I fix it?
Read the documentation. Popover presentation is only available for horizontally regular size classes. Currently, this is only on iPad. Popover presentation on iPhone will always be executed as full screen modal presentation. See here.
You are lucky that iOS8 doesn't crash, as iOS7 and below, if you used UIPopoverController on a phone idiom, your app would crash. UIPopoverController is deprecated in iOS8 in favor of popover modal presentation. This is why your app does not crash.
You could keep the same code for UIPopoverController as iOS 7
just set ViewController.preferredContentSize = CGSizeMake(300, 290);
It will work.
Other Solution
iOS 8 has a new PopOverController called UIPopoverPresentationController
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UINavigationController *navController = [storyboard instantiateViewControllerWithIdentifier:#"Terms_NC"];
navController.preferredContentSize = CGSizeMake(300, 290);
// Present the view controller using the popover style.
navController.modalPresentationStyle = UIModalPresentationPopover;
[self presentViewController:navController animated: YES completion: nil];
// Get the popover presentation controller and configure it.
UIPopoverPresentationController *presentationController =
[navController popoverPresentationController];
presentationController.permittedArrowDirections =0;
presentationController.sourceView = self.view;
presentationController.sourceRect = CGRectMake(100, 100, 300, 340);