Orientation in a UIView added to a UIWindow

43,809

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.

Share:
43,809

Related videos on Youtube

Ken
Author by

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, 2020

Comments

  • Ken
    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:

    enter image description here

    I do have a navigation controller but this view has been added to the UIWindow directly.

  • Adam
    Adam over 13 years
    That'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
    Fábio Oliveira over 11 years
    What about it getting the orientation change events?
  • Fábio Oliveira
    Fábio Oliveira over 11 years
    Adding 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
    Jon over 11 years
    your 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
    Fábio Oliveira over 11 years
    Ok. 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
    mAc over 11 years
    @FábioOliveira :- +1, Thanks for highlighting the drawback in this, i will keep this also in my mind. :)
  • Ameet Dhas
    Ameet Dhas about 11 years
    but if our application has UINavigationController, its showing NavigationBar on top of myView. Why this?
  • Kjuly
    Kjuly almost 11 years
    Hey @FábioOliveira, have you figured out any workaround on the situation you said?
  • Kjuly
    Kjuly almost 11 years
    This is a really great lib! Thx!
  • John Wordsworth
    John Wordsworth almost 11 years
    Very useful code for a project I am working on which needs to present views on top of whatever is currently showing. Brilliant. Thanks!
  • lottscarson
    lottscarson almost 11 years
    You're a lifesaver. Wish I'd found this a few hours ago!
  • jumponadoughnut
    jumponadoughnut almost 11 years
    The view seems to resize to fill the window on rotation. How do you maintain the original size?
  • hfossli
    hfossli almost 11 years
    That'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
    Ben Wheeler almost 11 years
    FYI, 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
    hfossli almost 11 years
    @BenjaminWheeler Ok. You are free to edit or update. The function you mention is already in this post.
  • odyth
    odyth over 10 years
    this 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
    Guillermo Ceballos over 10 years
    Definitely this the right answer. It deserves much more votes.
  • Utkarsh Goel
    Utkarsh Goel about 10 years
    Thanks hfossli & ThomasW. keep it up. +1
  • hfossli
    hfossli about 10 years
    @UtkarshGoel Thanks :)
  • khunshan
    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
    khunshan almost 10 years
    The 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
    ikzjfr0 over 9 years
    you may get count = 0 when [window subviews]
  • Chris Prince
    Chris Prince almost 9 years
    window = [[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.