iOS随笔

iOS屏幕旋转

2017-09-21  本文已影响89人  CoderXLL

一、UIDeviceOrientation 与 UIInterfaceOrientation的区别

UIDeviceOrientation 是机器硬件的当前旋转方向,这个枚举只能取值,不能手动设置,通过UIDeviceOrientationDidChangeNotification可以监听其方向的改变。网上有屌丝用以下方式进行修改,在这里不建议这样做

NSNumber *value = [NSNumber numberWithInt:UIDeviceOrientationPortrait];
[[UIDevice currentDevice] setValue:value forKey:@"orientation"];

UIDeviceOrientation枚举值如下:

typedef NS_ENUM(NSInteger, UIDeviceOrientation) {
    UIDeviceOrientationUnknown,
    UIDeviceOrientationPortrait,            // Device oriented vertically, home button on the bottom
    UIDeviceOrientationPortraitUpsideDown,  // Device oriented vertically, home button on the top
    UIDeviceOrientationLandscapeLeft,       // Device oriented horizontally, home button on the right
    UIDeviceOrientationLandscapeRight,      // Device oriented horizontally, home button on the left
    UIDeviceOrientationFaceUp,              // Device oriented flat, face up
    UIDeviceOrientationFaceDown             // Device oriented flat, face down
}

UIInterfaceOrientation 是程序界面当前旋转方向,通过UIApplicationDidChangeStatusBarOrientationNotification可以监听到即界面的布局方向发生了改变。(只有布局改变了才能收到通知)并且这个枚举是可以手动设置的。(可以理解为屏幕相对的home键方向)

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.
typedef NS_ENUM(NSInteger, UIInterfaceOrientation) {
    UIInterfaceOrientationUnknown            = UIDeviceOrientationUnknown,
    UIInterfaceOrientationPortrait           = UIDeviceOrientationPortrait,
    UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
    UIInterfaceOrientationLandscapeLeft      = UIDeviceOrientationLandscapeRight,
    UIInterfaceOrientationLandscapeRight     = UIDeviceOrientationLandscapeLeft
}

二、如果你的App不支持屏幕旋转,有以下两种方式处理

  1. 设置AppDelegate里的一下方法,返回值即为屏幕固定方向
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
    return UIInterfaceOrientationMaskLandscapeRight;
}
  1. General-Deployment Info-Device Orientation对支持的方向进行勾选

两种方式都可以触发UIDeviceOrientationDidChangeNotification通知

三、如果你的App需要屏幕自适应重力感应进行旋转,并且需要针对每个VC进行单独控制

当然这种情况你完全可以手动地对每个控制器的view布局,在监听到UIDeviceOrientationDidChangeNotification通知后做旋转处理。一两个界面还好,如果控制多的话,还是需要按一下方式处理

// 是否支持屏幕旋转
- (BOOL)shouldAutorotate
{
    return self.topViewController.shouldAutorotate;
}

/**
 适用于Push进去的子类调用

 @return 屏幕支持的旋转方向
 */
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return self.topViewController.supportedInterfaceOrientations;
}


/**
 适用于modal进去的子类调用

 @return 屏幕支持的旋转方向
 */
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return self.topViewController.preferredInterfaceOrientationForPresentation;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
    return (toInterfaceOrientation == UIInterfaceOrientationPortrait);
}

// 设置屏幕旋转方向
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

// 设置是否支持屏幕旋转
-(BOOL)shouldAutorotate
{
    return NO;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
    return (toInterfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}

// 设置屏幕旋转方向
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskAllButUpsideDown;
}

// 设置是否支持屏幕旋转
-(BOOL)shouldAutorotate
{
    return YES;
}
// 设置屏幕是否支持旋转
- (BOOL)shouldAutorotate
{
    return NO;
}

// 设置屏幕方向
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return UIInterfaceOrientationLandscapeLeft;
}

四、遇到的问题

自己写了一个视频录制的控制器,本来是通过UIDeviceOrientationDidChangeNotification监听手机旋转方向来对视频方向进行调整,实现视频的横竖屏录制(视频的方向枚举AVCaptureVideoOrientation,有兴趣的童鞋可以了解下)

typedef NS_ENUM(NSInteger, AVCaptureVideoOrientation) {
    AVCaptureVideoOrientationPortrait           = 1,
    AVCaptureVideoOrientationPortraitUpsideDown = 2,
    AVCaptureVideoOrientationLandscapeRight     = 3,
    AVCaptureVideoOrientationLandscapeLeft      = 4,
}

但是如果系统禁止了屏幕旋转功能,通知就监听不到旋转了,原因是因为此时系统会默认你当前的屏幕状态一直都是你锁屏时的状态。

解决方法

目前大多数用户的苹果手机基本都有螺旋仪和加速器,可以根据这个东西来判断,这时候需要引入CoreMotion.framework这个框架。

  1. 初始化一个螺旋仪对象
// 系统禁止屏幕旋转后,可以监听到屏幕方向
// 螺旋仪
@property (nonatomic, strong) CMMotionManager *motionManager;
- (void)initialMotionManager
{
    if (_motionManager == nil)
    {
        _motionManager = [[CMMotionManager alloc] init];
    }
    // 提供设备运动数据到指定的时间间隔(轮询间隔)
    _motionManager.deviceMotionUpdateInterval = 0.3;
    // 确定"是否使用任何可用的态度参考帧来决定设备的运动"是否可用?
    if (_motionManager.deviceMotionAvailable)
    {
        // 启动设备的运动更新,通过给定的队列向给定的处理程序提供数据
        [_motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMDeviceMotion * _Nullable motion, NSError * _Nullable error) {
           
            // 调用处理函数
            [self performSelectorOnMainThread:@selector(handleDeviceMotion:) withObject:motion waitUntilDone:YES];
        }];
    } else {
        self.motionManager = nil;
    }
}
  1. 根据重力感应来判断目前屏幕方向并可以做对应处理
- (void)handleDeviceMotion:(CMDeviceMotion *)deviceMotion
{
    double x = deviceMotion.gravity.x;
    double y = deviceMotion.gravity.y;
    // 竖屏
    if (fabs(y) >= fabs(x))
    {
        // 这个地方注意
//        if (y >= 0)
//        {
//            // UIDeviceOrientationPortraitUpsideDown;
//        } else {
//            // UIDeviceOrientationPortrait;
//        }
        self.recordOrientation = UIDeviceOrientationPortrait;
    } else {
        if (x >= 0)
        {
            self.recordOrientation = UIDeviceOrientationLandscapeRight;
        } else {
            self.recordOrientation = UIDeviceOrientationLandscapeLeft;
        }
    }
}

这里因为我本身的项目需求,只是全局记录下了屏幕当前方向,然后KVO监听recordOrientation,再对视频录制写入方向进行处理。

  1. 注意一定要在控制器消失前,关闭轮询。否则会造成内存泄漏
// 关闭螺旋仪
    [self.motionManager stopDeviceMotionUpdates];

至此,所有我要说的都表达完了。码农共勉!

上一篇下一篇

猜你喜欢

热点阅读