前言
这两天在学关于屏幕旋转的相关的知识,也延伸出了加速器和陀螺仪这些以前没有深入去学习过的知识点,在没有仔细看之前也有一些问题在想,比如;用户关闭了手机的屏幕旋转,但根据我们的使用经验,APP的界面还是可以旋转的,比如那些视屏播放类型的APP,还是可以全屏观看视频的,那这些是怎么做的?还有比如 你整个项目不允许横屏展示的,而某一个控制器却单独要求横屏展示,这个又该怎么做?用户关闭了手机屏幕旋转,我们还能不能判断手机屏幕的方向?带着这些问题我们一个一个的说一下屏幕方向的那些事儿。
从简单的开始
先说用户允许手机屏幕旋转的情况(明确一点,你APP允许旋转了,用户不允许屏幕旋转那你下面简单的勾选是没用的,至于怎么转,后面说!)
要是你的整个项目允许横竖屏,怎么设置,我想这个大家因该都清楚,下图勾选就是了。
接下来,要是用户改变了手机屏幕的方向,你需要做相应的一些操作,那你就得知道用户是横屏还是竖屏,这时候就有这个通知 UIDeviceOrientationDidChangeNotification 可以的上场了,每当用户改变了手机屏幕的方向之后,我们都可以通过这个通知去判断手机屏幕的方向:(前提是用户开启了手机屏幕旋转功能)要是没开启,这个通知我测试过你第一次打开APP的时候,这个通知是可以收到的,但因为你锁定屏幕之前,系统会强制竖屏的,不允许横屏关闭屏幕旋转!你第一次收到的通知也就变得没意义了,因为都关闭了旋转,都不会转了!怎么收到后序的通知!
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(orientchang:) name:UIDeviceOrientationDidChangeNotification object:nil];
上面接受到通知,下面就可以做相应的判断:
-(void)orientchang:(NSNotification *)odentifile { //获取 当前设备 实例 UIDevice *device = [UIDevice currentDevice] ; switch (device.orientation) { case UIDeviceOrientationFaceUp: NSLog(@"屏幕朝上平躺"); break; case UIDeviceOrientationFaceDown: NSLog(@"屏幕朝下平躺"); break; //无法判断目前设备的方向,有可能是让你斜置了 case UIDeviceOrientationUnknown: NSLog(@"未知方向"); break; case UIDeviceOrientationLandscapeLeft: NSLog(@"屏幕向左横置"); break; case UIDeviceOrientationLandscapeRight: NSLog(@"屏幕向右横置"); break; case UIDeviceOrientationPortrait: NSLog(@"屏幕直立"); break; case UIDeviceOrientationPortraitUpsideDown: NSLog(@"屏幕直立,上下顛倒"); break; default: NSLog(@"无法识别屏幕方向"); break; } }
说说上面的注意和延伸的点:
第一点:
UIDeviceOrientationDidChangeNotification 通知,点进去看的话,看到和它在一起的有下面几个通知,顺便也就在这里解释一下这几个通知给大家;
UIDeviceBatteryStateDidChangeNotification 电池状态改变到通知(像低于20%的低电量模式等)
UIDeviceBatteryLevelDidChangeNotification 电池的电量改变通知
UIDeviceProximityStateDidChangeNotification 这个是近距离传感器通知,就像打电话的时候,你把手机贴近脸的时候,屏幕会关闭,你把手机拿开之后会变亮,就是用的这个,后面还会给链接关于这块的知识!
其实像 UIApplicationDidChangeStatusBarFrameNotification 这个状态栏的改变通知也可以判断手机屏幕的方向!其实重点不是得用哪一个,都是在屏幕改变之后收到的通知,你收到通知之后知道屏幕方向变了立马再去判断获取手机屏幕的方向,这才是重点,也是核心吧!
UIKIT_EXTERN NSString *const UIDeviceOrientationDidChangeNotification __TVOS_PROHIBITED; UIKIT_EXTERN NSString *const UIDeviceBatteryStateDidChangeNotification NS_AVAILABLE_IOS(3_0) __TVOS_PROHIBITED; UIKIT_EXTERN NSString *const UIDeviceBatteryLevelDidChangeNotification NS_AVAILABLE_IOS(3_0) __TVOS_PROHIBITED; UIKIT_EXTERN NSString *const UIDeviceProximityStateDidChangeNotification NS_AVAILABLE_IOS(3_0);
第二点:
UIDevice *device = [UIDevice currentDevice] 这个还是有必要延伸一下里面的内容的,我们把它常用的属性也通过代码展示出来;
NSString *ZXName = [[UIDevice currentDevice] name]; NSLog(@"设备名称:%@", ZXName); NSString *ZXsysName = [[UIDevice currentDevice] systemName]; NSLog(@"系统名称:%@", ZXsysName);// 手机就是iPhone OS NSString *ZXSysVersion = [[UIDevice currentDevice] systemVersion]; NSLog(@"系统版本号:%@", ZXSysVersion);// 目前是9.3.4 NSString *ZXModel = [[UIDevice currentDevice] model]; NSLog(@"设备类型:%@", ZXModel);// iPhone NSString *ZXlocalizedModel = [[UIDevice currentDevice] localizedModel]; NSLog(@"本地设备模式:%@", ZXlocalizedModel);// iPhone /** * UUIDString 可用于唯一地标识该设备 */ NSUUID *identifierForVendor = [[UIDevice currentDevice] identifierForVendor]; NSLog(@"strIdentifierForVendor:%@", identifierForVendor.UUIDString);
关于这个 UUIDString 再多说两句,也上网搜了一下这个东西,答案是这样的:
NSString *identifierForVendor = [[UIDevice currentDevice].identifierForVendor UUIDString];
NSString *identifierForAdvertising = [[ASIdentifierManager sharedManager].advertisingIdentifier UUIDString];
解释说明:
identifierForVendor对供应商来说是唯一的一个值,也就是说,由同一个公司发行的的app在相同的设备上运行的时候都会有这个相同的标识符。然而,如果用户删除了这个供应商的app然后再重新安装的话,这个标识符就会不一致。
advertisingIdentifier会给这个设备上所有软件的供应商返回给相同的一个值,所以只能在广告的时候使用。这个值会因为很多情况而有所变化,比如说用户初始化设备的时候便会改变。
用户关闭了手机屏幕旋转怎么办?
这个我们也就从简单点的说起吧,说个简单的需求,用户把手机屏幕旋转关闭了,我们还有一个播放器界面还是需要横屏显示,我们该怎么办?先说简单的,我们有一个全屏的点击按钮,点击了按钮之后界面横屏。看代码解释,按钮的和点击事件就不写了,直接到重点:
// UIInterfaceOrientationLandscapeLeft 向左横置,具体向右或者向左的值自己取出来。 NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft]; [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
点击按钮,这个界面就变成了相应横屏的模式!其实这里也会相应的启发到你,那整个APP不允许旋转,唯独这一个界面要能横屏该怎么做?就简单了。这个任务就交给你实践了,要觉得不行,你再给留言或者加我QQ联系我!
CoreMotion.frameWork 主角该登场了!
这个框架就是处理加速器和陀螺仪的东西!先添加到自己的项目里面,导入系统头文件
#import <CoreMotion/CoreMotion.h>
iOS 开发----CMDeviceMotion陀螺仪的使用 iOS学习笔记34 - 加速计和陀螺仪
先把我的学习链接给大家,感谢作者!
至于陀螺仪和加速器是什么,这个我就不再描述了。原理大家可以看上面给的学习链接!说说怎么用它们判断手机屏幕的方向!看代码解释:
- (void)zxMotionManager{ if (_motionManager == nil) { _motionManager = [[CMMotionManager alloc] init]; } if ([_motionManager isGyroAvailable]) { // deviceMotion 加速器和陀螺仪的复合型数据 _motionManager.deviceMotionUpdateInterval = 0.01f; [self.motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMDeviceMotion * _Nullable motion, NSError * _Nullable error) { [self performSelectorOnMainThread:@selector(handleDeviceMotion:) withObject:motion waitUntilDone:YES]; }]; } else { NSLog(@"陀螺仪/加速器不可用"); [self setMotionManager:nil]; } } - (void)handleDeviceMotion:(CMDeviceMotion *)deviceMotion{ double x = deviceMotion.gravity.x; double y = deviceMotion.gravity.y; if (fabs(y) >= fabs(x)) { if (y >= 0){ NSLog(@"屏幕直立,上下顛倒"); } else{ NSLog(@"屏幕直立"); } } else { if (x >= 0){ NSLog(@"屏幕向右橫置"); } else{ NSLog(@"屏幕向左横置"); } } }
你在你需要的地方去调用 zxMotionManager 方法就能够判断出手机屏幕的方向,就算是用户关闭了手机旋转按钮!!
扩展一下:
下面的内容只是自己觉得好玩,区别看待!
在上面的学习链接里面,有这样的一个效果,图片看似随着你手机屏幕的转动而转动,但仔细看看好像方向是没变的!效果如下图
先把加速器和陀螺仪的代码给出来,但其实只是它们任何一个单独做的话效果不会很好,会感觉一闪一闪的!
- (void)creatMotionManager{ if (_motionManager == nil) { _motionManager = [[CMMotionManager alloc] init]; } if ([_motionManager isGyroAvailable]) { __weak typeof (self) weakSelf = self; // CMAccelerometerData 加速器效果 // _motionManager.accelerometerUpdateInterval = 0.01f; // [self.motionManager startAccelerometerUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMAccelerometerData * _Nullable accelerometerData, NSError * _Nullable error) { // // double rotation = atan2(accelerometerData.acceleration.x,accelerometerData.acceleration.y) - M_PI; // weakSelf.imageview.transform = CGAffineTransformMakeRotation(rotation); // }]; // 陀螺仪的效果 _motionManager.gyroUpdateInterval = 0.01f; [self.motionManager startGyroUpdatesToQueue:[NSOperationQueue currentQueue] withHandler:^(CMGyroData *gyroData, NSError *error) { double rotation = atan2(gyroData.rotationRate.x, gyroData.rotationRate.y) - M_PI; weakSelf.imageview.transform = CGAffineTransformMakeRotation(rotation); }]; } }
最后经过验证,还是它们俩复合型的数据效果比较棒!
- (void)creatMotionManager{ // deviceMotion 加速器和陀螺仪的复合型数据 _motionManager.deviceMotionUpdateInterval = 0.01f; [self.motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMDeviceMotion * _Nullable motion, NSError * _Nullable error) { double rotation = atan2(motion.gravity.x,motion.gravity.y) - M_PI; weakSelf.imageview.transform = CGAffineTransformMakeRotation(rotation); }]; }
有兴趣的可以自己试一下,要看到上面有什么问题了,加我Q或者留言给我! !