Orientation in a UIView added to a UIWindow
Solution 1
You can read about some of the possible causes here:
Technical Q&A QA1688 - Why won't my UIViewController rotate with the device?
In your situation its probably the fact that you are adding the view as another subview to the window. Only the first subview gets the rotation events. What you can do is add it as a subview of the first window subview.
UIWindow* window = [UIApplication sharedApplication].keyWindow;
if (!window)
window = [[UIApplication sharedApplication].windows objectAtIndex:0];
[[[window subviews] objectAtIndex:0] addSubview:myView];
Solution 2
The problem
Beginning with iOS 6, only the topmost view controller (alongside the UIApplication object) participates in deciding whether to rotate in response to a change of the device's orientation.
https://developer.apple.com/library/content/qa/qa1688/_index.html
The solution
I have open sourced a pod named AGWindowView.
It will automatically deal with any rotation and framechanges so you won't have to worry about that.
The code
It supports any combination of SDK's and iOS system versions. The relevant code can be found here: https://github.com/hfossli/AGWindowView/blob/master/Source/AGWindowView.m
Solution 3
I created a category on UIApplication that has a helper property and method for getting the first subview of the keyWindow. This is the view you want to overlay anyway. Now when you add a view that is managed by a UIViewController to that view, the shouldRotateToInterfaceOrientation: method is called.
UIApplication+WindowOverlay.h
#import <UIKit/UIKit.h>
@interface UIApplication(WindowOverlay)
@property (nonatomic, readonly) UIView *baseWindowView;
-(void)addWindowOverlay:(UIView *)view;
@end
UIApplication+WindowOverlay.m
#import "UIApplication+WindowOverlay.h"
@implementation UIApplication(WindowOverlay)
-(UIView *)baseWindowView{
if (self.keyWindow.subviews.count > 0){
return [self.keyWindow.subviews objectAtIndex:0];
}
return nil;
}
-(void)addWindowOverlay:(UIView *)view{
[self.baseWindowView addSubview:view];
}
@end
and here is how you would use it.
//at the top of the file...or in {yourproject}.pch
#import "UIApplication+WindowOverlay.h
//in a method:
UIView *view = [UIView new];
UIView *window = [UIApplication sharedApplication].baseWindowView;
view.frame = window.bounds;
[window addSubview:view];
//or
[[UIApplication sharedApplication] addWindowOverlay:view];
Solution 4
This is because as you mention your view has been added directly to the UIWindow, therefore when the method to rotate is called for the navigation controller nothing happens to the uiview. The UIView would rotate if it was a subview of the view controller view. If for some reason this cannot be done. Then you could override this method:
// This method is called every time the device changes orientation
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
}
And every time your orientation changes also change your view orientation.
Related videos on Youtube
Ken
Beer snob, professional tanner like Zonker Harris, semi-pro napper. Hoping to go ProNap after the next US Nap Open.
Updated on July 02, 2020Comments
-
Ken almost 4 years
I have a UIView which is supposed to cover the whole device (UIWindow) to support an image zoom in/out effect I'm doing using core animation where a user taps a button on a UITableViewCell and I zoom the associated image.
The zooming is performing flawlessly, what I haven't been able to figure out is why the subview is still in portrait mode even though the device is in landscape. An illustration below:
I do have a navigation controller but this view has been added to the UIWindow directly.
-
Kev almost 12 yearsDoes this answer help at all? stackoverflow.com/a/3368786/419 if so could you accept that instead?
-
-
Adam over 13 yearsThat's amazing - thanks for pointing the QA link. In official docs, it's undocumented (I've scoured the View and Window programming guides, and the UIWindow and UIView classes, couldn't find any mention of it), and clearly a massive bug (that Apple has no intention of fixing, judging by the tone of the QA article).
-
Fábio Oliveira over 11 yearsWhat about it getting the orientation change events?
-
Fábio Oliveira over 11 yearsAdding to the first subview won't work if you want to show in front of a modal view controller (at least from iOS5 onwards) as modal view controllers are added as a second view hierarchy on the main UIWindow subviews.
-
Jon over 11 yearsyour view will be rotated and the autoresize mask will be honored if you use this. it is based on what should have been the accepted answer from above. I don't have an answer for getting rotation events specifically, but i'm sure it's been answered somewhere else.
-
Fábio Oliveira over 11 yearsOk. I missed the part that was a subview of the window's first subview. Then a problem with this approach is that you cannot present it from a modal view controller. Maybe if you add it as a subview of the last window's subviews. This way if you have a modal view controller showing you have two subviews on the main window: the root view controller view and the dimming view of the modal view controller and you want to add it to the dimming view, so it shows on top.
-
mAc over 11 years@FábioOliveira :- +1, Thanks for highlighting the drawback in this, i will keep this also in my mind. :)
-
Ameet Dhas about 11 yearsbut if our application has UINavigationController, its showing NavigationBar on top of myView. Why this?
-
Kjuly almost 11 yearsHey @FábioOliveira, have you figured out any workaround on the situation you said?
-
Kjuly almost 11 yearsThis is a really great lib! Thx!
-
John Wordsworth almost 11 yearsVery useful code for a project I am working on which needs to present views on top of whatever is currently showing. Brilliant. Thanks!
-
lottscarson almost 11 yearsYou're a lifesaver. Wish I'd found this a few hours ago!
-
jumponadoughnut almost 11 yearsThe view seems to resize to fill the window on rotation. How do you maintain the original size?
-
hfossli almost 11 yearsThat's the point. :) If you want a specific view to maintain the original size then I suggest you add it as a subview.
-
Ben Wheeler almost 11 yearsFYI, there's a bunch of stuff in the code above that references methods not found in standard ios libraries. I assume things like UIInterfaceOrientationAngleOfOrientation are found in the full code that hfossli wrote.
-
hfossli almost 11 years@BenjaminWheeler Ok. You are free to edit or update. The function you mention is already in this post.
-
odyth over 10 yearsthis wont work on iOS 7 if you have an UIAlertView up as that will be the key window. [[UIApplication sharedApplication] windows][0] will always return the Application's window.
-
Guillermo Ceballos over 10 yearsDefinitely this the right answer. It deserves much more votes.
-
Utkarsh Goel about 10 yearsThanks hfossli & ThomasW. keep it up. +1
-
hfossli about 10 years@UtkarshGoel Thanks :)
-
khunshan almost 10 years@Fabio agree. i am adding a subview in a subview added to view. It adds as a sibling of first subview, not as a child.
-
khunshan almost 10 yearsThe link mentioned here is "Why won't my UIViewController rotate with the device?". What the question is "Why won't my UIView rotate with the device?" I am sad that it is about UIView property of UIViewController. And encourages about one rootViewController. My application has one container vew controller as rootViewController. But the problem is UIView added to UIWindow is not working. Its an independent Subview extended from UIView. That is completely separate case.
-
ikzjfr0 over 9 yearsyou may get count = 0 when [window subviews]
-
Chris Prince almost 9 yearswindow = [[UIApplication sharedApplication].windows objectAtIndex:0]; on iOS7, in landscape is still in portrait (frame is 768x1024 on iPad). And the bounds are also 768x1024 and the transform is the identity transform.