I'm building an iPad app on iOS8, landscape, upgrading from iOS7. I've replaced UIAlertView (deprecated) with UIAlertController in a number of other places in my app which has fixed this issue. However, I also use a UIWebView which apparently shows its own UIAlertViews. When this happens I also get the same problem (see partial pic, cropped). The alert view is misplaced lower to the left and only the left 2/3 of the screen is dimmed, and worse, the right most portion that is not dimmed still responds to touch gestures, so it's possible to control the app behind the modal!
The alert that the UIWebView throws is a standard "wants to use your location" alert. How do I fix this for UIWebView? Thanks!
EDIT: problem typically occurs when the app is brought to active state after trying to show the alert while backgrounded
I met a similar issue with iPhone, this happens when the application supports multiple rotation mask and is forced to strictly one. Basically, the viewController for example has shouldAutoRotate = NO, this only affects the view controller not the current window which is the alertView presented by the UIWebView.
Try implementing application:supportedInterfaceOrientationsForWindow
Here is an example:
-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
return (enablesRotation == YES) ? UIInterfaceOrientationMaskAllButUpsideDown : UIInterfaceOrientationMaskLandscape;
}
This tells that the current window must follow the desired supported orientation mask. Hopes this helps.
I need to know if there is a way to tell a iOS7 device to set a views orientation without the device being rotated. Some way in code to trigger the device to calling the code that tells it which way to display the view.
If the device is in landscape and remains held in landscape orientation while a certain change happens I want to force a change to show the view in portrait orientation, at which point the user would need to turn the device to look at it properly. I'll explain why below
Looking at my app might make my description clearer - it is free to download
I have a number of view controllers (embedded in navigationControllers) and only one of them needs to be rotated into landscape and then only under certain conditions.
Solutions here on StackOverflow seem to be to make a category on UINavigationController giving it shouldAutorotate and supportedInterfaceOrientations methods and then use those methods in the individual viewControllers to block or allow rotations.
This has worked for me .... however
On the one view controller I wish to rotate , I don't want it to rotate all the time.
This view controller is the diveSiteDetailsController, (if you have downloaded the app you need to select dive sites on the first page then click the '+' to see it). It has a UISegmentedController and 4 subviews (3 tableviews and 1 other UIView). The current version on the App Store works fine now i've solved this - but looking at it may help you understand my issue better).
On diveSiteDetailViewController the UISegmentedController is used to switch between the 4 subviews.
All the subviews are used to enter data about the same dive site but as there is a lot of potential data, I have broken it into logical chucks each of which is a subview - location, data (depths,currents, visibility), type of environment and notes.
The .hidden property of each subview is used to make them appear and disappear.
I only want the second subview to rotate (the data view - it has some sliders on it that are easier to work with if in landscape).
restricting this rotation is easy - iI achieved it like this
- (NSUInteger)supportedInterfaceOrientations{
if (self.dsDataRangeSlidingTV.hidden) {
return UIInterfaceOrientationMaskPortrait;
}
return UIInterfaceOrientationMaskAllButUpsideDown;
}
Now the view will only rotate to landscape when the data table view is displayed.
However, once in landscape, if I chose a different subview with the UISegmentedController then they are, obviously, shown in landscape also as the iOS device hasn't done a rotation. This is the situation I am trying to avoid.
Rotating the iOS device will return those views to portrait as expected but i need to trigger the device to to reevaluate its display when I use the UISegmentedController to switch from the data subview to another subview and its that triggering that I don't know how to do.
any suggestions greatly received.
Heres a workaround that is working for me
I've added the following few lines to the end of my method that responds to the UISegmentedControl being tapped.
UIViewController *aDummyController = [[UIViewController alloc]init];
[self presentViewController:aDummyController animated:NO completion:nil];
[self dismissViewControllerAnimated:NO completion:nil];
adding a new viewController and popping it off triggers the rotation . This is a kludgey way of achieving what I wanted.
I found the solution in this post
Is there a documented way to set the iPhone orientation?
all credit to Josh who although not the accepted answer is the one that 99 people currently have up voted.
I still have a bug in that, if I were holding the device in landscape (although the display is portrait view) whilst on the screen that segues into the diveSiteDetailsController then the initial view the diveSiteDetailsController display will be in landscape.
To get around this I created a Bool property called notThisTime on the diveSiteDetailsController and set it to true in the prepareFor Segue on the viewController that called it.
i then did changed supportedInterfaceOrientation to
- (NSUInteger)supportedInterfaceOrientations
{// DLog(#"Running %# '%#'", self.class, NSStringFromSelector(_cmd));
if (self.notThisTime){
return UIInterfaceOrientationMaskPortrait;
}
if (!self.dsDataRangeSlidingTV.hidden) {
return UIInterfaceOrientationMaskAllButUpsideDown;
}
then at the end of the ViewDidLoad method I added
self.notThisTime = NO;
I would still love to hear from anyone with a suggestion how better to handle this. pushing and popping a dummy view to get the iPhone to do an orientation check seems like a work around for something that should just be available as a standard method call.
One final Note - the iOS simulator does not like this - you need to check on the device - it sometimes tries to draw the iPhone container in landscape while the screen is drawn vertically - however it does work fine on the iPhone
I have a universal app with seperate xibs for iPhone and iPad
For the iPad version, I want my one of my iPad xibs in landscape mode. I have set it to landscape in simulated metrics, (The app is set for portrait in the summary screen) and the landscape view still shows in portrait when run. Im sure I read on here a naming convention that tells the app the xib is in landscape ie: view1_one.xib~ipad-landscape
Ive tried using screen rotation methods but iOS 6 screen rotation is just proving so frustrating as I have tried so many solutions all of which have no effect. I have done screen rotation before in iOS 6 but I was using storyboards and subclassed a navigation controller for my chosen view, I dont know how to do this with this code as I picked it ip from someone else
So to sum up: How can I get my screen to respect the landscape xib I have created in interface builder instead of showing it in portrait
I would point out I have searched on here for a solution and spent many hours on this before posting this
There are naming conventions for resources (including xib's) that specify on which device type they are loaded. However, these do not exist for specific orientations. -landscape won't do anything extra (more specifically, it will probably load the resource on an iPhone as well, which isn't what you want).
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/LoadingResources/Introduction/Introduction.html#//apple_ref/doc/uid/10000051i-CH1-SW2
As for handling orientation changes, make sure you implement both the iOS 5 and below methods and the iOS 6 methods for handling them:
// Older versions of iOS (deprecated)
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
return UIInterfaceOrientationIsLandscape(toInterfaceOrientation);
}
// iOS6
- (BOOL)shouldAutorotate {
return YES;
}
// iOS6
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscape;
}
// Added after comment
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationLandscapeLeft;
}
This is the official way to ensure that your viewController is only loaded in landscape.
Edit:
I added the preferredInterfaceOrientationForPresentation method as well. While personally I don't like this method, it forces the viewController to present in that orientation, until the next orientation change. Not nice, but it will help you to see if your orientation methods get called at all.
Also try to set a breakpoint in each of these methods. If they don't get called at all, your issue might be with the subclassing. Be certain that the viewController in the storyboard is set to the subclass and not the superclass.
Edit2:
Check this in Interface Builder:
When I'm in landscape mode on iPad and trying to launch app I'm getting strange behavior:
My root view controller view is created with dimensionality equal to 768x1024 whereas it should be 1024x768 (device is in landscape mode). Because of that my view hierarchy is corrupted.
View is created by the system (I'm using nib for interface).
Does it bug in iOS, or, maybe, I'm doing something wrong?
Edit: Autoresizing mask is default (everything resizes).
Found a solution here Reporting incorrect bounds in landscape Mode.
I was checking view controller view size in viewDidLoad, while correct sizes available only in viewDidAppear.
That is ok. It is always creates views in portrait orientation when perform rotation to lanscape. So U should implement
- (BOOL) shouldAutorotateToInterfaceOrientation (UIInterfaceOrientation)
- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)
And check in code
This question is about iOS device rotation and multiple controlled views in a UINavigationController. Some views should be constrained to portrait orientation, and some should autorotate freely. If you try and create the simplest setup with three views, you'll notice that the autorotation behavior has a few very nasty quirks. The scenario is, however, very simple, so I think I'm either not doing the autorotation implementation correctly, or I'm forgetting something.
I have a very basic demo app that shows the weirdness, and I made a video showing it in action.
Download the app (XCode project)
View the classes as a gist (rather lengthy)
Watch the question video (YouTube, 2m43s)
The setup is very basic: Three view controllers called FirstViewController, SecondViewController and ThirdViewController all extend an AbstractViewController that shows a label with the class' name and that return YES for shouldAutorotateToInterfaceOrientation: when the device is in portrait orientation. The SecondViewController overrides the this method to allow for all rotations. All three concrete classes add a few colored squares to be able to navigate between the views by pushing and popping the controllers onto/off the UINavigationController. So far a very simple scenario, I would say.
If you hold the device in portrait or landscape orientation, this is the result I would not only like to achieve, but would also expect. In the first image you see that all views are 'upright', and in the second you see that only the second view controller counter-rotates the device's orientation. To be clear, it should be possible to navigate from the second view in landscape mode to the third, but because that third only supports portrait orientation, it should only be shown in portrait orientation. The easiest way to see if the results are alright, is by looking at the position of the carrier bar.
But this question is here because the actual result is completely different. Depending on what view you're at when you rotate the device, and depending on what view you navigate to next, the views will not rotate (to be specific, the didOrientFromInterfaceOrientation: method is never called). If you're in landscape on the second and navigate to the third, it will have the same orientation as the second (=bad). If you navigate from the second back to the first however, the screen will rotate into a 'forced' portrait mode, and the carrier bar will be at the physical top of the device, regardless of how you're holding it. The video shows this in more detail.
My question is twofold:
Why does the first view controller rotate back, but not the third?
What needs to be done to get the correct behavior from your views when you only want some views to autorotate, but not others?
Cheers,
EP.
EDIT: As a last resort before putting a bounty on it, I completely rewrote this question to be shorter, clearer and hopefully more inviting to give an answer.
The short answer is that you're using UINavigationController, and that won't work like you want it to. From Apple's docs:
Why won't my UIViewController rotate with the device?
All child view controllers in your
UITabBarController or
UINavigationController do not agree on
a common orientation set.
To make sure that all your child view
controllers rotate correctly, you must
implement
shouldAutorotateToInterfaceOrientation
for each view controller representing
each tab or navigation level. Each
must agree on the same orientation for
that rotate to occur. That is, they
all should return YES for the same
orientation positions.
You can read more about view rotation issues here.
You'll have to roll your own view/controller stack management for what you want to do.
Make a bolean in App delegate to control which orientation you want for example make a bool to enable Portrait and in your view controller you want to allow Portrait enable it by shared application
in your view controller,where you want to enable or disable what ever orientation you want.
((APPNAMEAppDelegate *)[[UIApplication sharedApplication] delegate]).enablePortrait= NO;
in App Delegate.
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
NSLog(#"Interface orientations");
if(!enablePortrait)
return UIInterfaceOrientationMaskLandscape;
return UIInterfaceOrientationMaskLandscape|UIInterfaceOrientationMaskPortrait;
}
These method will be fired each time you rotate the device, Based on these BOOL enable the orientation you want.
There was a similar question a few years ago with a number of answers. Here is a recent answer from someone to that question:
Is there a documented way to set the iPhone orientation?
From what I understand, this is a problem a lot of people have and mostly hacks are the only way to fix it. Look through that thread if you haven't seen it before and see if anything works for you.
On a side note, I had a similar problem a while back when I was calling something in shouldAutorotate and I added some code to viewWillAppear to try to fix it. I honestly can't remember if it worked and I don't have a Mac anymore to try it out, but I found the code and I'll paste it here in case it gives any inspiration.
- (void)viewWillAppear:(BOOL)animated{
UIInterfaceOrientation o;
switch ([UIDevice currentDevice].orientation) {
case UIDeviceOrientationPortrait:
o = UIInterfaceOrientationPortrait;
break;
case UIDeviceOrientationLandscapeLeft:
o = UIInterfaceOrientationLandscapeLeft;
break;
case UIDeviceOrientationLandscapeRight:
o = UIInterfaceOrientationLandscapeRight;
break;
default:
break;
}
[self shouldAutorotateToInterfaceOrientation:o];
}
DO NOT USE THIS HACK, APPLE WILL REJECT THE APP BASED ON THE USE OF 'PRIVATE API'
For the sake of reference, I will leave my answer here, but the use of private API will not slip past the review board. I learnt something today :D As #younce quoted the Apple docs correctly, what I want cannot be achieved with the UINavigationController.
I had two options. First, I could have written my own navigation controller substitute, with all the horrors that one would have encountered while doing it. Secondly, I could have hacked the rotation into the view controllers, using an undocumented feature of UIDevice called setOrientation:animated:
Because the second was temptingly easy, I went for that one. This is what I did. You'll need a category to suppress compiler warnings about the setter not existing:
#interface UIDevice (UndocumentedFeatures)
-(void)setOrientation:(UIInterfaceOrientation)orientation animated:(BOOL)animated;
-(void)setOrientation:(UIInterfaceOrientation)orientation;
#end
Then you need to check for the supported orientations on viewWillAppear:. Next to the UIDevice methods used here, you could also force portrait orientation by presenting a modal view controller, but that will happen instantly and not animated, so this is my preferred way:
-(void)viewWillAppear:(BOOL)animated {
UIDevice *device = [UIDevice currentDevice];
UIDeviceOrientation realOrientation = device.orientation;
if ([self shouldAutorotateToInterfaceOrientation:realOrientation]) {
if (realOrientation != [UIApplication sharedApplication].statusBarOrientation) {
// Resetting the orientation will trigger the application to rotate
if ([device respondsToSelector:#selector(setOrientation:animated:)]) {
[device setOrientation:realOrientation animated:animated];
} else {
// Yes if Apple changes the implementation of this undocumented setter,
// we're back to square one.
}
}
} else if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationPortrait]) {
if ([device respondsToSelector:#selector(setOrientation:animated:)]) {
// Then set the desired orientation
[device setOrientation:UIDeviceOrientationPortrait animated:animated];
// And set the real orientation back, we don't want to truly mess with the iPhone's balance system.
// Because the view does not rotate on this orientation, it won't influence the app visually.
[device setOrientation:realOrientation animated:animated];
}
}
}
The trick is to always keep the internal device orientation to the 'real' orientation of the device. If you start changing that, the rotation of your app will be out of balance.
But as I know now, this is just a sure way to get your app rejected. So option number two is just a bad option. Rewrite that NavigationController, or just have all your views support the same orientation set.
Cheers, EP.
In iOS 6, this has become a very simple issue. Simply create a special class for the views you want to autorotate. Then, in your rootVC, add this.
-(BOOL)shouldAutorotate{
BOOL should = NO;
NSLog(#"%#", [self.viewControllers[self.viewControllers.count-1] class]);
if ([self.viewControllers[self.viewControllers.count-1] isKindOfClass:[YourAutorotatingClass class]]) {
should = YES;
}
return should;
}
I know this is an old question, but I thought it worthwhile to mention.