6

I know that this looks like a huge question but it's not so don' be afraid to read it. Mostly it's me explaining how stuff works.

I have two UIWindows in my app. The first one is the main window which gets created by the app by default. The second one is called modalWindow and is also created in the app delegate.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.


    self.modalWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.modalWindow.windowLevel = UIWindowLevelStatusBar;

    //Other stuff I need
    //....

    return YES;
}

Most of my app is portrait only but there is one view controller where the user can switch to landscape orientation. I'm listening for landscape change via:

[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];

This works fine and in the orientationChanged method I present the landscape view controller. All is well at this point. If I rotate back to portrait I get the orientationChanged fired once more at which point I dismiss the landscape view controller.

Now let's explain how the second window comes into play. When in landscape mode there is an action (just a button press) which presents a new view controller on the second window (the modalWindow). Ok let's explain this.

The app delegate has two methods which look like so:

- (void)presentActivityOnModalWindow:(UIViewController *)viewController
{
    self.modalWindow.rootViewController = viewController;
    self.modalWindow.hidden = NO;
}

- (void)modalTransitionFinished:(NSNotification *)notif
{
    self.modalWindow.hidden = YES;
    self.modalWindow.rootViewController = nil;
}

I call the presentActivityOnModalWindow via the [[[UIApplication sharedApplication] delegate] performSelector....]. I know it isn't the best practice but it works fine. As for the dismissal I use NSNotificationCenter to post the notification about dismissal. The view controller that gets presented on the modalWindow is supporting only portrait mode. It's returning YES in shouldAutorotate and UIInterfaceOrientationMaskPortrait in supportedInterfaceOrientations.

Ok a lot of explaining but now we get to the problem. When I rotate to landscape, pop up the modalWindow, dismiss the modal window and rotate back to portrait my main window is still in landscape mode and everything looks catastrophic.

I tried adding an observer to both window and modalWindow and logging changes in frame and bounds and here are the results:

Did finish launching:
window frame {{0, 0}, {320, 568}}
window bounds {{0, 0}, {320, 568}}
modalWindow frame {{0, 0}, {320, 568}}
modalWindow bounds {{0, 0}, {320, 568}}

Rotate to landscape:
window frame {{0, 0}, {568, 320}}

Open activity in landscape:
modalWindow frame {{0, 0}, {320, 568}}
modalWindow frame {{0, 0}, {320, 568}}

Dismiss activity:
none


Rotate back to portrait:
none

So as it seems my window does not get back to normal frame when we get back to portrait mode. How to fix this? If I need to provide any more details feel free to ask.

Majster
  • 3,611
  • 5
  • 38
  • 60

3 Answers3

1

The system will only handle rotation of your keyWindow. If you have other windows you'll have to handle rotation yourself.

I also think that modal controllers is the way to go. But if you really want to handle rotations take a look at how other "custom windows" libraries handle rotation. Alert views are a great example:

https://github.com/search?o=desc&q=uialertview&s=stars&type=Repositories&utf8=

Rivera
  • 10,792
  • 3
  • 58
  • 102
0

Apple does not encourage using windows in this manner. It is probably best to use an UIViewController displayed modally in stead of your

self.modalWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

Presenting an UIViewController modally is done from an UIViewController instance using

[self presentViewController:<#(UIViewController *)#> animated:<#(BOOL)#> completion:<#^(void)completion#>]
gabriel_101
  • 773
  • 3
  • 19
-1

You are creating 2 windows and Apple recommends against this. An app should really have as many windows as there are display devices.(SEE UIWindow reference )

I would suggest using 2 views and "drawing" everything onto those views according to the orientation. Then make one view hidden, when the other is displayed.

Alternatively you could just use 1 view and make adjustments at the time of orientation changes. The ease of doing this depends on the type of information being displayed. Orientation changes are best detected by AppDelegate code.

Here is a sample of code I use to detect an orientation change and then a check for the new dimensions of the window.

- (void)application:(UIApplication *)application didChangeStatusBarOrientation:(UIInterfaceOrientation)oldStatusBarOrientation
{

    //other stuff from rotate:
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];

    CGRect appFrame = [[UIScreen mainScreen ]applicationFrame];//using frame so status bar is not part of calculations.

    if (orientation == UIInterfaceOrientationLandscapeRight
        ||
        orientation == UIInterfaceOrientationLandscapeLeft
        )
    {
        self.currentAppScreenWidth  = appFrame.size.height;
        self.currentAppScreenHeight = appFrame.size.width;
        [YOURapp reArrangeSubViews_and_Layouts: appFrame];//Something like this - maybe.
    }
    else
    {
        self.currentAppScreenWidth = appFrame.size.width;
        self.currentAppScreenHeight = appFrame.size.height;
        [YOURapp reArrangeSubViews_and_Layouts: appFrame];//Something like this - maybe.

     }
}

Hope that helps. One other thing. If you are displaying the same info with a different layout, then you should be able to lay it out using Xcode tools, to adapt to orientation in a suitable way. If certain things are still not perfect, then try to tweak using code. If you are displaying completely different information, the 2 view approach might be the easiest.

[Maybe some more information about the differences in the data being displayed on the 2 screens, if the above solution does not work for you. Cheers.]

BitKick
  • 39
  • 10