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

下面还会举例说明。

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

第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 ,有兴趣的朋友欢迎来探讨。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 总结iOS App开发中控制屏幕旋转的几种方式

    在iOS6之前的版本中,通常使用 shouldAutorotateToInterfaceOrientation 来单独控制某个UIViewController的方向,需要哪个viewController支持旋转,只需要重写shouldAutorotateToInterfaceOrientation方法. 但是iOS 6里屏幕旋转改变了很多,之前的 shouldAutorotateToInterfaceOrientation 被列为 DEPRECATED 方法,查看UIViewController

  • 关于iOS屏幕旋转的一些注意事项

    前言 最近有个需求,是在App中有一个查看文件的页面,由于查看文件横屏会更方便阅读,所以boss说要让这个页面可以横屏.之前都没有接触过横屏的具体实现方法,一开始走了不少弯路,而且各种bug.在这里把遇到的问题分享一下,希望对大家有点帮助. 要让你的APP支持旋转,你需要进行如下几个步骤 1. 全局配置 在工程->TARGETS->General->Deployment Info中配置 在AppDelegate中配置 - (UIInterfaceOrientationMask)appli

  • iOS开发中控制屏幕旋转的编写方法小结

    在iOS5.1 和 之前的版本中, 我们通常利用 shouldAutorotateToInterfaceOrientation: 来单独控制某个UIViewController的旋屏方向支持,比如: 复制代码 代码如下: - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation  {      return (interfaceOrientation == UIInter

  • iOS开发中使用屏幕旋转功能的相关方法

    加速计是整个IOS屏幕旋转的基础,依赖加速计,设备才可以判断出当前的设备方向,IOS系统共定义了以下七种设备方向:   复制代码 代码如下: typedef NS_ENUM(NSInteger, UIDeviceOrientation) { UIDeviceOrientationUnknown, UIDeviceOrientationPortrait,            // Device oriented vertically, home button on the bottom UIDe

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

    在做视频开发时遇到屏幕旋转问题,其中涉及到 StatusBar. UINavigationController.UITabBarController .UIViewcontroller . 在设备锁屏下的整体效果图 iOS-旋转.gif 主要涉及以下4点: 横竖屏的旋转 屏幕旋转相应改变视图位置 旋转时状态栏的隐藏与显示 锁屏 1.横竖屏旋转 第1步: -(UIInterfaceOrientationMask)application:(UIApplication *)application su

  • iOS中关于音乐锁屏控制音乐(锁屏信息设置)的实例代码

    废话不多说了,直接给大家贴代码了,具体代码如下所示: <pre name="code" class="objc">appDelegate里面加入如下代码获取后台播放权限</pre><pre name="code" class="objc">- (void)setAudioBackstagePlay{ AVAudioSession *audioSession = [AVAudioSession

  • iOS监听手机锁屏状态

    iPhone的锁屏监测分为两种方式监听: 1. 程序在前台,这种比较简单.直接使用Darwin层的通知就可以了: #import <notify.h> #define NotificationLock CFSTR("com.apple.springboard.lockcomplete") #define NotificationChange CFSTR("com.apple.springboard.lockstate") #define Notifica

  • Android 监听屏幕是否锁屏的实例代码

    今天,简单讲讲如何监听手机屏幕是否锁屏. 实现方法: 1)通过BroadcastReceiver接收广播Intent.ACTION_SCREEN_ON和Intent.ACTION_SCREEN_OFF可以判断屏幕状态是否锁屏,但是只有屏幕状态发生改变时才会发出广播: 2)如果要在屏幕状态发生改变之前就想获取屏幕状态,可以通过反射机制调用PowerManager的isScreenOn方法 . 具体实现,见代码: 直接上代码: 1.定义一个接收广播的类 package com.app.lib; im

  • C++实现截图截屏的示例代码

    目录 1.截图工具 1.1 键盘截图(PrtScn键) 1.2 win10自带截图(Win+Shift+S) 1.3 系统自带的截图小工具 1.4 ffmpeg 1.5 ScreenToGif 1.6 Chrome 2.C++.GDI 2.1 微软官方例子 2.2 C++.GDI.CImage 3.C++.OpenGL 4.C++.OpenCV 5.C++.QT 1.截图工具 1.1 键盘截图(PrtScn键) 如何使用Microsoft Windows操作系统中的Print Screen(打印

  • IOS获取系统相册中照片的示例代码

    先来看看效果图 下面话不多少,我们直接上代码: #import "ViewController.h" @interface ViewController ()<UINavigationControllerDelegate,UIImagePickerControllerDelegate> @property (weak, nonatomic) IBOutlet UIImageView *IconView; @end @implementation ViewController

  • iOS整个APP实现灰色主题的示例代码

    灰色主题 背景 在一些哀悼日,清明节的时候app会实现一些灰色主题功能,部分app需求是tab首页实现灰色模式就可以,但一些需求是直接整个app都变为灰色模. 普通UI界面 web页面 xib界面 attributeText加载的htmlString页面 attachment挂件页面 实现方式 基本的实现方式1,普通页面用hook颜色方式2.web页面用注入灰色js实现方式 图片变灰 重新绘制图片变为灰色代码实现 //image类别 - (UIImage *)getGrayImage { con

  • C# wpf使用ffmpeg命令行实现录屏的示例代码

    目录 前言 一.主要步骤 1.使用 AllowsTransparency实现穿透框 2.获取音频设备名称 3.命令行启动ffmpeg 4.使用JobObject管理子进程 二.完整代码 三.效果预览 1.录制中 2.录制动态流程 总结 前言 上一章我们实现了截屏界面与功能,接下来可以在此基础上实现录屏功能,录屏采用ffmpeg命令行实现会方便一些,效果也是不错的,当然前提是要对Windows子进程的控制比较熟悉,做出来之后完全可以满足项目使用. 一.主要步骤 1.使用 AllowsTranspa

  • rust延迟5秒锁屏的实现代码

    先给大家介绍下rust延迟5秒锁屏的实现代码: main.rs #![windows_subsystem = "windows"] use std::process::Command; use std::os::windows::process::CommandExt; use std::thread::sleep; use std::time::Duration; fn main() {     let time_seconds = Duration::from_secs(5);  

  • JS实现的添加弹出层并完成锁屏操作示例

    本文实例讲述了JS实现的添加弹出层并完成锁屏操作.分享给大家供大家参考,具体如下: 上图: 代码: <html> <head> <title>弹出层</title> <style type="text/css"> *{ padding:0px; margin:0px; } .up{ width:500px; height: 400px; border:1px solid silver; position: absolute;

随机推荐