Autorotation of complex interfaces in iPad programs

    Most iPhone and iPod touch programs only support portrait orientation. Many developers did not even think about adding landscape (landscape) orientation where it is really needed. Apple is no exception, which in iPhone OS 2.x did not provide the best examples without realizing support for landscape (landscape) orientation in important system programs (in iPhone OS 3.x, the company corrected its mistake).

    With the advent of the iPad, the situation has changed. Apple has obliged all developers to support all device orientations in iPad programs. Naturally, there may be exceptions, for example, games. But programs that do not have a rigid binding (functional) to the orientation should be user friendly in any position of the device.

    With simple interfaces, there are no difficulties. Objects of the UIView class are set with the necessary autoresizingMask property, which describes the change in the frame. For complex interfaces, this method is no longer suitable.

    I will tell you how to make a smooth and pleasant autorotation of the program interface using the layoutSubviews method. You can get detailed information about this method in the iPad Programming Guide . I will only give a real practical example of its use (Apple's documentation is stingy in this regard).

    This is one of the options, but the result of his work is very high quality. Naturally, this option is suitable for iPad and iPhone / iPod touch.

    Suppose we want to have the following portrait and landscape (landscape) views: Immediately lay out the final project



    RotateDemo .

    And the video:


    Let's create a basic project for iPad (Window-based).

    I'm used to doing the whole interface programmatically. If you want, you can easily replace part of the code with a mouse click in Interface Builder.

    Add the class files ContainerView (derived from UIView) to the project. Leave it empty for now. An object of this class will be a container of all UIView objects in our controller. It is in this class that we reassign the layoutSubviews method.

    Create class files DemoViewController (derived from UIViewController).

    Our interface file DemoViewController.h:

    #import
    #import "ContainerView.h"

    @interface DemoViewController : UIViewController
    {
      ContainerView *containerView;
    }

    @end

    * This source code was highlighted with Source Code Highlighter.


    In the implementation of the class, only one main loadView method is important to us:

    - (void)loadView
    {
      CGRect screenRect = [[UIScreen mainScreen] applicationFrame];

      UIView *contentView = [[UIView alloc] initWithFrame:screenRect];
      contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
      contentView.backgroundColor = [UIColor blueColor];
      self.view = contentView;
      [contentView release];

      containerView = [[ContainerView alloc] initWithFrame:CGRectMake(0, 0, screenRect.size.width, screenRect.size.height)];
      containerView.backgroundColor = [UIColor blueColor];  
      containerView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
      [self.view addSubview:containerView];
      
      UIButton *button1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
      button1.frame = CGRectZero;
      [button1 setTitle:@"Object 1" forState:UIControlStateNormal];
      button1.tag = 1001;
      [containerView addSubview:button1];
      
      UIButton *button2 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
      button2.frame = CGRectZero;
      [button2 setTitle:@"Object 2" forState:UIControlStateNormal];
      button2.tag = 1002;  
      [containerView addSubview:button2];

      UIButton *button3 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
      button3.frame = CGRectZero;
      [button3 setTitle:@"Object 3" forState:UIControlStateNormal];
      button3.tag = 1003;  
      [containerView addSubview:button3];

      UIButton *button4 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
      button4.frame = CGRectZero;
      [button4 setTitle:@"Object 4" forState:UIControlStateNormal];
      button4.tag = 1004;  
      [containerView addSubview:button4];  
    }

    * This source code was highlighted with Source Code Highlighter.


    Everything is simple here. We create a container and add all our elements to it. In the example, these are just 4 UIButton buttons. Button frames do not matter (they will be set in the layoutSubviews method).

    Go back to our ContainerView class and override the layoutSubviews method:

    - (void)layoutSubviews
    {
      [super layoutSubviews];
      
      if (self.frame.size.width == 768)
      {  
        UIView *view = [self viewWithTag:1001];
        view.frame = CGRectMake(184, 100, 400, 150);
        
        view = [self viewWithTag:1002];
        view.frame = CGRectMake(184, 300, 400, 150);
        
        view = [self viewWithTag:1003];
        view.frame = CGRectMake(184, 500, 400, 150);
        
        view = [self viewWithTag:1004];
        view.frame = CGRectMake(184, 700, 400, 150);
      }
      else
      {
        UIView *view = [self viewWithTag:1001];
        view.frame = CGRectMake(74, 100, 400, 150);
        
        view = [self viewWithTag:1002];
        view.frame = CGRectMake(550, 100, 400, 150);

        view = [self viewWithTag:1003];
        view.frame = CGRectMake(74, 400, 400, 150);
        
        view = [self viewWithTag:1004];
        view.frame = CGRectMake(550, 400, 400, 150);
      }
    }

    * This source code was highlighted with Source Code Highlighter.


    The example uses a comparison with the absolute width. Alternatively, you can use a universal check:

    if (UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation]))

    * This source code was highlighted with Source Code Highlighter.


    Done. It remains only to activate our controller in the delegate class:

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {    
      controller = [[DemoViewController alloc] initWithNibName:nil bundle:nil];
      window.backgroundColor = [UIColor blueColor];
      [window addSubview:controller.view];
      [window makeKeyAndVisible];
      
      return YES;
    }

    * This source code was highlighted with Source Code Highlighter.


    So we got a smooth animation of changing the complex interface when changing orientation. Minimum code and nothing complicated.

    Also popular now: