IOS screen rotation has always been a clear and vague concept. It seems simple, but there are always problems with docking, such as screen flickering, rotation not working, status bar disappearing and a series of disgusting bugs. The project in charge of the author belongs to the mixed development mode of Reactnative&&ObjectC. Currently, the main app is required to display vertically by default, and a ViewController supporting automatic vertical and horizontal screens is provided to Reactnative. This is to sort out the iOS screen rotation, hope to be helpful to all developers.

One, disgusting three enumeration parsing

1. DeviceOrientation (physical rotation) – UIDeviceOrientation

  • Hardware device (iPad, iPhone) back rotation direction, with Home as the reference
//Portrait means Portrait and Landscape means Landscape. typedef NS_ENUM(NSInteger, UIDeviceOrientation) { UIDeviceOrientationUnknown, // Device oriented vertically, home button on the top UIDeviceOrientationPortraitUpsideDown, // Device oriented horizontally, home button on the right UIDeviceOrientationLandscapeLeft, // Device oriented horizontally, home button on the left UIDeviceOrientationLandscapeRight, // Device oriented flat, face up UIDeviceOrientationFaceUp, // Device oriented flat, face down UIDeviceOrientationFaceDown } __TVOS_PROHIBITED;Copy the code
  • The rotation direction of the device is read-only and cannot be written
Method to get the current screen: [UIDevice currentDevice].orientationCopy the code
  • Device rotation monitor
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onDeviceOrientationDidChange) name:UIDeviceOrientationDidChangeNotification object:nil]; [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; Listening method - (BOOL) onDeviceOrientationDidChange {/ / get the current equipment Device UIDevice * Device = [UIDevice currentDevice]; // Identify the current device orientation switch (device.orientation) {case UIDeviceOrientationFaceUp:
            NSLog(@"Lie flat with screen up.");
            break;

        case UIDeviceOrientationFaceDown:
            NSLog(@"Lie flat with the screen facing down.");
            break;

        caseUIDeviceOrientationUnknown: / / system currently cannot towards identification equipment, may be inclined NSLog (@"Direction unknown");
            break;

        case UIDeviceOrientationLandscapeLeft:
            NSLog(@"Screen horizontal to the left");
            break;

        case UIDeviceOrientationLandscapeRight:
            NSLog(@"Screen horizontal to the right");
            break;

        case UIDeviceOrientationPortrait:
            NSLog(@"Screen upright");
            break;

        case UIDeviceOrientationPortraitUpsideDown:
            NSLog(@"Screen upright, upside down.");
            break;

        default:
            NSLog(@"Unrecognizable");
            break;
    }
    return YES;
}
Copy the code

2. Page Rotation (View Rotation) – UIInterfaceOrientation

  • UIInterfaceOrientation Current orientation of the application interface (configurable)
// Note that UIInterfaceOrientationLandscapeLeft is equal to UIDeviceOrientationLandscapeRight (and vice versa). // This  is because rotating the device to the left requires rotating the content to the right. typedef NS_ENUM(NSInteger, UIInterfaceOrientation) { UIInterfaceOrientationUnknown = UIDeviceOrientationUnknown, UIInterfaceOrientationPortrait = UIDeviceOrientationPortrait, UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown, UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight, UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft } __TVOS_PROHIBITED;Copy the code
  • The orientation of the application interface uses UIInterfaceOrientation and has nothing to do with the orientation of the device
In order to achieve smooth effect UIInterfaceOrientationLandscapeLeft UIDeviceOrientationLandscapeRight = page, UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeftCopy the code

3, page rotation polymerization (after iOS6) – UIInterfaceOrientationMask

Supports multiple page rotation directions

typedef NS_OPTIONS(NSUInteger, UIInterfaceOrientationMask) {

    UIInterfaceOrientationMaskPortrait = (1 << UIInterfaceOrientationPortrait),

    UIInterfaceOrientationMaskLandscapeLeft = (1 << UIInterfaceOrientationLandscapeLeft),

    UIInterfaceOrientationMaskLandscapeRight = (1 << UIInterfaceOrientationLandscapeRight),

    UIInterfaceOrientationMaskPortraitUpsideDown = (1 << UIInterfaceOrientationPortraitUpsideDown),

    UIInterfaceOrientationMaskLandscape = (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight),

    UIInterfaceOrientationMaskAll = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskPortraitUpsideDown),

    UIInterfaceOrientationMaskAllButUpsideDown = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight),

} __TVOS_PROHIBITED;

Copy the code

Two, single page rotation direction setting

  • Implementation method
// method 1 - (BOOL)shouldAutorotate NS_AVAILABLE_IOS(6_0) __tvos_NLF3; / / method 2 - (UIInterfaceOrientationMask) supportedInterfaceOrientations NS_AVAILABLE_IOS __TVOS_PROHIBITED _0 (6); / / Returns the interface orientation masks. 3 - (UIInterfaceOrientation) preferredInterfaceOrientationForPresentation / / method NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED; !Copy the code
  • Method resolution
Method 1: Whether the page supports automatic rotation method 2: Which rotation directions the page supports Method 3: The rotation direction displayed on the page preferentiallyCopy the code

Three, two kinds of screen rotation trigger mode

1. The system does not turn off the automatic screen rotation function

ShouldAutorotate {(BOOL)shouldAutorotate {shouldAutorotate {(BOOL)shouldAutorotate {returnYES; } / / 2. Return to support the direction of rotation of / / the device, the default return value UIInterfaceOrientationMaskAllButUpSideDwon / / the device, The default return value is the UIInterfaceOrientationMaskAll - (UIInterfaceOrientationMask) supportedInterfaceOrientations {returnUIInterfaceOrientationMaskAll; } / / 3. To return to the interface of entering the default display direction - (UIInterfaceOrientation) preferredInterfaceOrientationForPresentation {return UIInterfaceOrientationPortrait;
}
Copy the code

2. The system disables the automatic screen rotation function

In the program interface by clicking and other ways to switch to landscape screen

// method 1: - (void)setInterfaceOrientation:(UIDeviceOrientation)orientation {
      if ([[UIDevice currentDevice]   respondsToSelector:@selector(setOrientation:)]) {
          [[UIDevice currentDevice] setValue:[NSNumber numberWithInteger:orientation]     
                                       forKey:@"orientation"]; }} // method 2: - (void)setInterfaceOrientation:(UIInterfaceOrientation)orientation {
   if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {
            SEL selector = NSSelectorFromString(@"setOrientation:");
            NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice     
        instanceMethodSignatureForSelector:selector]];
            [invocation setSelector:selector];
            [invocation setTarget:[UIDevice currentDevice]];
            int val = orientation;
            [invocation setArgument:&val atIndex:2]; [invocation invoke]; }}Copy the code
  • Make sure the shouldAutorotate method returns YES
  • Both use parameter types no

Priority of screen rotation control

1. Setting mode of screen rotation

- Xcode General Settings - Xcode nfo. Plist Settings - Code Settings in AppdelegeteCopy the code

2. Rotate the priority

Project Target property configuration (Global permissions) > Appdelegate&&Window > Root View Controller > Normal View ControllerCopy the code

3. Enable the global permission for App rotation

  • Device Orientation Attribute configuration
It is worth noting that for iPhone, if we select all or none of the four attributes, the effect will be the same as the defaultCopy the code
  • The Info. The Plist Settings
Supported Interface orientation has the same effect as the first method, both methods end up setting attributes in info.plistCopy the code
  • In the Appdelegate && Window Settings
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow  *)window {return  UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft;

}
Copy the code

If we implement the Appdelegate method, our App’s global rotation Settings will be the same as here, even if the first two methods are different.

5. Set the rotation permission of a single page

Controllers often involved in development

UITabbarViewController,UINavigationBarController ,UIViewController
Copy the code

Our project is done with UITabbarViewController as root view controller of the Window, and then manages several UINavigationBarController navigation controller, And then the navigation controller manages the normal view controller UIViewController. If so, for example, about rotary priority from high to low is UITabbarViewController > UINavigationBarController > UIViewController. If the high-priority controller turns rotation off, the low-priority controller cannot do it.

For example, if we want a single view controller torotate automatically, we should add shouldAutorotate to the view controller to return YES or NO. But if we have an upper root view controller, and we implement the method only in this view controller, we’ll find that the method doesn’t walk because it’s blocked by the upper root view controller

Six, automatic and controllable rotation

Step by step implementation

  • 1, UITabbarViewController
-(BOOL)shouldAutorotate{returnself.selectedViewController.shouldAutorotate; What screen direction -} / / support (UIInterfaceOrientationMask) supportedInterfaceOrientations {return[self.selectedViewController supportedInterfaceOrientations]; } / / the default direction - (UIInterfaceOrientation) preferredInterfaceOrientationForPresentation {return [self.selectedViewController preferredInterfaceOrientationForPresentation];
}
Copy the code
  • 2, UINavigationController
// return the rotation property of the topViewController of the navigation controller, because the navigation controller is stacked on the stack VC //topViewController is its topViewController, -(BOOL)shouldAutorotate{returnself.topViewController.shouldAutorotate; What screen direction -} / / support (UIInterfaceOrientationMask) supportedInterfaceOrientations {return[self.topViewController supportedInterfaceOrientations]; } / / the default direction - (UIInterfaceOrientation) preferredInterfaceOrientationForPresentation {return [self.topViewController preferredInterfaceOrientationForPresentation];
}
Copy the code

Basically, the higher-priority view controller follows the rotation configuration of the lower-priority controller. That will do the trick

2. Use modal views

Using modal views is not limited by this root view controller priority. It's also easy to understand that modal pop-up view controllers are isolated from the root view control. The Settings are the same as normal viewfinder codeCopy the code

7. Fulfill requirements

The main interface of the App is displayed vertically, and some pages are displayed horizontally

Two solutions

1. Step-by-step control

  • Step way
Enable the rotation direction supported by the global permission setting item. 2. Customize the label controller and navigation controller to set automatic rotation. 3. The custom base controller does not support automatic screen transfer and supports portrait 4 by default. Enable automatic screen rotation for the controller that needs screen rotation, set the supported rotation direction, and set the default rotation directionCopy the code

2. Monitor the current direction change globally

  • Step way
1. Add an attribute to the Applegate file that records whether the current screen is landscape 2. If a landscape screen is required, force the landscape screen upon entering the screen and restore the portrait screen upon leaving the screenCopy the code
  • The core code
1, add to monitor the [[NSNotificationCenter defaultCenter] addObserver: self selector: @ the selector (onDeviceOrientationDidChange) name:UIDeviceOrientationDidChangeNotification object:nil]; [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; 2, implementation, monitoring - (UIInterfaceOrientationMask) application: (UIApplication *) application supportedInterfaceOrientationsForWindow:(UIWindow *)window {if(_allowAutoRotate) {// Landscape only is supportedreturn UIInterfaceOrientationMaskLandscape;
    }else{// Portrait is supportedreturnUIInterfaceOrientationMaskPortrait; }} 3, page control - (void)viewWillAppear:(BOOL) Animated {[super viewWillAppear:animated]; AppDelegate* delegate = (AppDelegate*)[UIApplication sharedApplication].delegate; delegate.allowAutoRotate = YES; // Enter the interface: set landscape [self]setDeviceInterfaceOrientation:UIDeviceOrientationLandscapeLeft]; } - (void)viewWillDisappear:(BOOL)animated{ [super viewWillDisappear:animated]; AppDelegate* delegate = (AppDelegate*)[UIApplication sharedApplication].delegate; delegate.allowAutoRotate = NO; // Leave the screen: set portrait [selfsetDeviceInterfaceOrientation:UIDeviceOrientationPortrait];
}
Copy the code

Eight, optimize the display

The view switchover is abnormal

The current viewController works as expected. However, when the viewController returns to the previous page or enters the previous page in a direction that is not supported by the current page, the viewController cannot work as expected immediately. You need to change the device direction to restore the viewController

#pragma mark -UITabBarControllerDelegate
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
    [self presentViewController:[UIViewController new] animated:NO completion:^{
        [self dismissViewControllerAnimated:NO completion:nil];
    }];
}
#pragma mark -UINavigationControllerDelegate
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    [self presentViewController:[UIViewController new] animated:NO completion:^{
        [self dismissViewControllerAnimated:NO completion:nil];
    }];
}
Copy the code

However, the screen flicker may occur. This solution is not recommended. You can manually set the screen orientation in the hook function of the view

The status bar cannot be displayed after the screen is rotated

  • Set View Controller-based status bar appearance YES in info.plist
  • Corresponding control which implements the following code
// Set style - (UIStatusBarStyle)preferredStatusBarStyle {returnUIStatusBarStyleLightContent; } // Set whether to hide - (BOOL)prefersStatusBarHidden {// [super prefersStatusBarHidden];returnNO; } / / set hidden animation - (UIStatusBarAnimation) preferredStatusBarUpdateAnimation {return UIStatusBarAnimationNone;
}

Copy the code

The original link: tech.meicai.cn/detail/83, you can also search the small program “Mei CAI product technical team” on wechat, full of dry goods and updated every week, want to learn technology you do not miss oh.