iOS屏幕旋转与锁屏的示例代码

在做视频开发时遇到屏幕旋转问题,其中涉及到 StatusBar、 UINavigationController、UITabBarController 、UIViewcontroller 。

在设备锁屏下的整体效果图

iOS-旋转.gif

主要涉及以下4点:

  • 横竖屏的旋转
  • 屏幕旋转相应改变视图位置
  • 旋转时状态栏的隐藏与显示
  • 锁屏

1、横竖屏旋转

第1步:

-(UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {

// NSLog(@"0000000---------%@",NSStringFromClass([[self topViewController] class]));

// if ([NSStringFromClass([[self topViewController] class]) isEqualToString:@"FirstViewController"]) {

// //横屏

// return UIInterfaceOrientationMaskLandscapeRight;

// }

// //竖屏

// return UIInterfaceOrientationMaskPortrait;

NSUInteger orientations = UIInterfaceOrientationMaskAllButUpsideDown;

if(self.window.rootViewController){

//取出当前显示的控制器

UIViewController *presentedViewController = [self topViewControllerWithRootViewController:self.window.rootViewController];

//按当前控制器支持的方向确定旋转方向(将旋转方向重新交给每个控制器自己控制)

NSLog(@"%s, line = %d",__FUNCTION__,__LINE__);

orientations = [presentedViewController supportedInterfaceOrientations];

}

return orientations;

}

//获取界面最上层的控制器

//- (UIViewController*)topViewController {

// NSLog(@"%s, line = %d",__FUNCTION__,__LINE__);

// return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController];

//}

//一层一层的进行查找判断

- (UIViewController*)topViewControllerWithRootViewController:(UIViewController*)rootViewController {

NSLog(@"%s, line = %d",__FUNCTION__,__LINE__);

if ([rootViewController isKindOfClass:[UITabBarController class]]) {

UITabBarController* tabBarController = (UITabBarController*)rootViewController;

NSLog(@"Tabbar:%@",NSStringFromClass([tabBarController.selectedViewController class]));

return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];

} else if ([rootViewController isKindOfClass:[UINavigationController class]]) {

UINavigationController* nav = (UINavigationController*)rootViewController;

NSLog(@"nav:%@",NSStringFromClass([nav.visibleViewController class]));

return [self topViewControllerWithRootViewController:nav.visibleViewController];

} else if (rootViewController.presentedViewController) {

NSLog(@"present:%@",NSStringFromClass([rootViewController.presentationController class]));

UIViewController* presentedViewController = rootViewController.presentedViewController;

return [self topViewControllerWithRootViewController:presentedViewController];

} else {

NSLog(@"root:%@",rootViewController);

return rootViewController;

}

}

代码中通过 -(UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window 方法将控制器交给自己控制,该方法默认值为 Info.plist 中配置的 Supported interface orientations 项的值。

第2步:在各控制器设置支持的方向

//是否允许旋转(默认允许)

- (BOOL)shouldAutorotate {

return YES;

}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations{

//允许旋转的方向

return UIInterfaceOrientationMaskAll;

}

其中 - supportedInterfaceOrientations 方法在 iPad 中默认取值为 UIInterfaceOrientationMaskAll ,即默认支持所有屏幕方向;而 iPhone 跟 iPod Touch 的默认取值为 UIInterfaceOrientationMaskAllButUpsideDown ,即支持除竖屏向下以外的三个方向。

在设备屏幕旋转时,系统会调用 - shouldAutorotate 方法检查当前界面是否支持旋转,只有 - shouldAutorotate 返回 YES 的时候, - supportedInterfaceOrientations 方法才会被调用,以确定是否需要旋转界面。

这个是 TabbarController 中设置的,它会影响关联的 UIViewController 的支持方向,需要在 UIViewController 中进一步设置

//此方法来控制能否横竖屏 控制锁屏

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {

NSLog(@"%s, line = %d",__FUNCTION__,__LINE__);

UIInterfaceOrientationMask inter;

if (_lockScreen) {

switch (_lockOrientation) {

case 1:

inter = UIInterfaceOrientationMaskPortrait;

break;

case 2:

inter = UIInterfaceOrientationMaskPortraitUpsideDown;

break;

case 3:

inter = UIInterfaceOrientationMaskLandscapeRight;

break;

case 4:

inter = UIInterfaceOrientationMaskLandscapeLeft;

break;

default:inter = UIInterfaceOrientationMaskAll;

break;

}

} else {

inter = UIInterfaceOrientationMaskAll;

}

//支持全部方向

return inter;

}

第3步:强制转换控制器方向

- (void)setInterOrientation:(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;

// 从2开始是因为0 1 两个参数已经被selector和target占用

[invocation setArgument:&val atIndex:2];

[invocation invoke];

}

}

这样就可以完成横竖屏的切换。

2、屏幕旋转相应改变视图位置

这里先扩展 UIDeviceOrientation & UIInterfaceOrientation 的知识

UIDeviceOrientation 设备的物理方向

UIDeviceOrientation 即我们手持的移动设备的 Orientation ,是一个三围空间,有六个方向,通过 [UIDevice currentDevice].orientation 获取当前设备的方向。

typedef NS_ENUM(NSInteger, UIDeviceOrientation) {

UIDeviceOrientationUnknown,

UIDeviceOrientationPortrait,

UIDeviceOrientationPortraitUpsideDown, // Device oriented vertically, home button on the top 竖屏向下,即头在下,Home 键在上

UIDeviceOrientationLandscapeLeft, // Device oriented horizontally, home button on the right 横屏头在左,Home键在右

UIDeviceOrientationLandscapeRight, // Device oriented horizontally, home button on the left 横屏头在右,Home键在左

UIDeviceOrientationFaceUp, // Device oriented flat, face up

UIDeviceOrientationFaceDown // Device oriented flat, face down

} ;

UIInterfaceOrientation 界面的显示方向

UIInterfaceOrientation 即我们看到的视图的 Orientation ,可以理解为 statusBar 所在的方向,是一个二维空间,有四个方向, 通过 [UIApplication sharedApplication].statusBarOrientation 即状态栏的方向获取当前界面方向。

// 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

}

UIInterfaceOrientationMask 支持的方向

// iOS 6 之后用于控制界面的枚举值

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

}

由上可以发现:

iOS 6 及之后版本使用的 UIInterfaceOrientationMask 类型来控制屏幕屏幕方向,该类型也新增加了几个枚举取值,可用一个枚举取值来代表多个屏幕方向,使用起来更方便。

注意在 UIInterfaceOrientation 中有注释

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,大意是界面的左转相当于设备的右转,如果设备向左转时就需要内容(即界面)向右转。即:

UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight

UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft

下面还会举例说明。

其实 UIDeviceOrientation 与 UIInterfaceOrientation 是两个互不相干的属性,通常情况下会一起出现,在这里正好利用此特性在屏幕旋转后进行重新布局。

第1步:监听 UIDeviceOrientationDidChangeNotification 状态

//监听设备旋转 改变 视图 对应位置

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange) name:UIDeviceOrientationDidChangeNotification object:nil];

//用来控制横竖屏时调整视图位置

- (void)deviceOrientationDidChange

{

[self isPortrait];

}

第2步:重新布局

if (_interOrientation == UIInterfaceOrientationPortrait || _interOrientation == UIInterfaceOrientationPortraitUpsideDown) {

self.top.constant = 145;

self.bottom.constant = 210;

} else if (_interOrientation == UIInterfaceOrientationLandscapeRight || _interOrientation == UIInterfaceOrientationLandscapeLeft) {

self.top.constant = 40;

self.bottom.constant = 50;

}

例如:竖屏转横屏

界面竖屏 UIInterfaceOrientationPortrait ->横屏 UIInterfaceOrientationLandscapeRight ,设备方向 UIDeviceOrientationPortrait -> UIDeviceOrientationLandscapeLeft ,在设备发生变化这个过程触发 UIDeviceOrientationDidChangeNotification 监听,然后进行重新布局。

3、旋转时状态栏的隐藏与显示

这里只记述旋转时状态栏的变化,由竖屏想横屏变化时状态栏会消失。

//在需要的`UIViewController`设置是否隐藏

- (BOOL)prefersStatusBarHidden {

NSLog(@"%s, line = %d",__FUNCTION__,__LINE__);

return NO;

}

4、锁屏

锁屏时,不管系统锁屏是否关闭、Push 或 Present 返回后,界面依然保持不变。

第1步:设置锁屏

- (IBAction)lockAction:(UIButton *)sender {

if (_lockScreen) {

_lockScreen = NO;

[sender setTitle:@"锁定屏幕" forState:UIControlStateNormal];

} else {

_lockScreen = YES;

[sender setTitle:@"解开屏幕" forState:UIControlStateNormal];

}

_lockOrientation = _interOrientation;

}

第2步:绕过强转

- (void)interfaceOrientation:(UIInterfaceOrientation)orientation

{

[self isPortrait];

//锁屏情况下 不旋转

if (!_lockScreen) {

[self setInterOrientation:orientation];

}

第3步:针对 Push 或 Present 返回后

- (void)viewWillAppear:(BOOL)animated {

if (_lockScreen) {

//记录返回时的界面状态

[self setInterOrientation:_lockOrientation];

} else {

[self isPortrait];

}

}

5、 针对特定 UIViewController 方向的支持

-(UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {

if ([NSStringFromClass([[self topViewController] class]) isEqualToString:@"FirstViewController"]) {

//横屏

return UIInterfaceOrientationMaskLandscapeRight;

}

//竖屏

return UIInterfaceOrientationMaskPortrait;

}

最后的献上 GitHub 代码,还有2个小的 bug ,有兴趣的朋友欢迎来探讨。

以上是 iOS屏幕旋转与锁屏的示例代码 的全部内容, 来源链接: utcz.com/z/346440.html

回到顶部