您的位置:首页 > 移动开发 > IOS开发

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

2018-07-13 11:15 1511 查看

在做视频开发时遇到屏幕旋转问题,其中涉及到

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 屏幕旋转 锁屏