屏幕方向該知道的那些事兒


前言

    這兩天在學關於屏幕旋轉的相關的知識,也延伸出了加速器和陀螺儀這些以前沒有深入去學習過的知識點,在沒有仔細看之前也有一些問題在想,比如;用戶關閉了手機的屏幕旋轉,但根據我們的使用經驗,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或者留言給我! !


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM