31

I am adding an additional UIWindow to my app. My main window rotates correctly, but this additional window I have added does not rotate.

What is the best way to rotate a UIWindow according to the current device orientation?

aryaxt
  • 76,198
  • 92
  • 293
  • 442
  • 2
    Why would you add another UIWindow? – Moshe Jul 14 '11 at 18:12
  • 8
    "Every iOS application needs at least one window—an instance of the UIWindow class—and some may include more than one window." ([View Programming Guide for iOS](http://developer.apple.com/library/ios/#documentation/WindowsViews/Conceptual/ViewPG_iPhoneOS/CreatingWindows/CreatingWindows.html#//apple_ref/doc/uid/TP40009503-CH4-SW1)) – titaniumdecoy Jul 14 '11 at 18:15
  • That doesn't answer the question of why one would *want* another window, though. The most common use case appears to be for video-out. – Danilo Campos Jul 14 '11 at 18:45
  • Charming. But I read the question. I was responding to Moshe. – Danilo Campos Jul 14 '11 at 18:53
  • 5
    @Moshe Creating another window is a common technique when trying to position content 'above' a UIPopoverController (which itself creates a separate UIWindow). Drag-and-drop from UIPopoverController is the canonical example – Jaysen Marais Apr 11 '12 at 08:39

5 Answers5

45

You need to roll your own for UIWindow.

Listen for UIApplicationDidChangeStatusBarFrameNotification notifications, and then set the the transform when the status bar changes.

You can read the current orientation from -[UIApplication statusBarOrientation], and calculate the transform like this:

#define DegreesToRadians(degrees) (degrees * M_PI / 180)

- (CGAffineTransform)transformForOrientation:(UIInterfaceOrientation)orientation {

    switch (orientation) {

        case UIInterfaceOrientationLandscapeLeft:
            return CGAffineTransformMakeRotation(-DegreesToRadians(90));

        case UIInterfaceOrientationLandscapeRight:
            return CGAffineTransformMakeRotation(DegreesToRadians(90));

        case UIInterfaceOrientationPortraitUpsideDown:
            return CGAffineTransformMakeRotation(DegreesToRadians(180));

        case UIInterfaceOrientationPortrait:
        default:
            return CGAffineTransformMakeRotation(DegreesToRadians(0));
    }
}

- (void)statusBarDidChangeFrame:(NSNotification *)notification {

    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];

    [self setTransform:[self transformForOrientation:orientation]];

}

Depending on your window´s size you might need to update the frame as well.

Morten Fast
  • 6,322
  • 27
  • 36
  • @morten-fast Thanks for the tip. But I could not figure out how to treat coordination system ofter rotation... `x` becomes `y` and `width` becomes `height`? Or no? – oleynikd May 14 '15 at 19:53
  • OK. I've made some research and seems like app's main `UIWindow` handles orientation changes without rotations... So there should be some other way??? Anyone? – oleynikd May 14 '15 at 20:24
  • 1
    @oleynikd On iOS8 and above, if you set your windows rootViewController to the UIViewController it's being presented on, it will handle rotation for you (though I've experienced some bugs with this - in particular on my view controller that launches the app and if I pop up the keyboard) – Ser Pounce May 15 '15 at 04:45
18

Just create a UIViewController with its own UIView, assign it as rootViewController to your window and add all further UI to the view of the controller (not directly to the window) and the controller will take care of all rotations for you:

UIApplication * app = [UIApplication sharedApplication];
UIWindow * appWindow = app.delegate.window;

UIWindow * newWindow = [[UIWindow alloc] initWithFrame:appWindow.frame];
UIView * newView = [[UIView alloc] initWithFrame:appWindow.frame];
UIViewController * viewctrl = [[UIViewController alloc] init];

viewctrl.view = newView;
newWindow.rootViewController = viewctrl;

// Now add all your UI elements to newView, not newWindow.
// viewctrl takes care of all device rotations for you.

[newWindow makeKeyAndVisible];
// Or just newWindow.hidden = NO if it shall not become key

Of course, exactly the same setup can also be created in interface builder w/o a single line of code (except for setting frame sizes to fill the whole screen before displaying the window).

Mecki
  • 125,244
  • 33
  • 244
  • 253
  • Just curious, but why do you say to add all of your subviews to newView instead of newWindow? – Ser Pounce May 15 '15 at 04:48
  • @CoDEFRo Because the rotation is performed by the ViewController (`viewctrl`) and this ViewController only rotates the view it controls (which is `newView`), which will then rotate all its subviews recursively. If you add them directly to to `newWindow`, then your views don't get rotated by the ViewController and you will have to rotate them by hand again (a UIWindow doesn't rotate any views when you rotate the device, it doesn't even rotate itself). – Mecki May 15 '15 at 13:55
4

You need set new window's rootViewController.Then the window's subviews will rotate correctly.

myNewWindow!.rootViewController = self

Then you can change frames in the rotate methods.

e.g. (swift in ios8)

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { customAlertView.frame = UIScreen.mainScreen().bounds }

hstdt
  • 5,652
  • 2
  • 34
  • 34
1

You can set the rootController for your UIWindow. e.g:

fileprivate(set) var bottonOverlayWindow = UIWindow()

self.bottonOverlayWindow.rootViewController = self; 

// 'self' will the ViewController on which you had added UIWindow view. So whenever you ViewController change the orientation, your window view also change it's orientation.

Let me know if you face any issue.

Nishant Sharma
  • 189
  • 2
  • 6
1

I don't know that you do anything with the window. But the root controller needs to respond to shouldAutorotate with a YES.

Hot Licks
  • 47,103
  • 17
  • 93
  • 151