1. 程式人生 > >iOS 【陀螺儀 自身旋轉角&水平面夾角 問題】

iOS 【陀螺儀 自身旋轉角&水平面夾角 問題】

在開發過程中,我們通常會遇到 獲取 iPhone 繞自身的旋轉角度 以及 獲取 iPhone 與水平面的夾角 這類需求。打個比方,在專案中,我們需要整合一個相機拍攝照片的功能。前提條件是讓只允許相機在橫屏狀態下進行拍攝,而豎屏狀態下禁止拍攝。如果要實現這個需求,那麼僅僅靠系統內建的相機 API 是無法實現的,那麼我們就需要自定義相機。而本文就是解決在自定義相機時如何顯示手機自身的狀態,並拿到這個狀態進而決定是否允許拍攝。

如下圖,分別是在我自定義相機拍攝時橫豎屏的一個介面展示狀態,正好描述了上文描述的一個情景:



可以發現,在豎屏狀態下時,會有一層灰黑色的蒙版,上面有提醒橫屏拍攝的標識語,按鈕也是禁用狀態,只有退出按鈕可用。而在橫屏狀態下時,拍照按鈕可用,提示標語和蒙版均消失。那麼,究竟怎麼才能實現橫豎屏的判定呢?

程式碼:

//
//  PushViewController.m
//  陀螺儀
//
//  Created by CoderZYWang on 2016/12/26.
//  Copyright © 2016年 CoderZYWang. All rights reserved.
//

#import "PushViewController.h"

#import <CoreMotion/CoreMotion.h>

@interface PushViewController ()

@property (nonatomic, strong) CMMotionManager *motionManager;

@end

@implementation PushViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    // 當前的view必須設定背景色,不然根本沒法觸發螢幕的點選事件
    self.view.backgroundColor = [UIColor whiteColor];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self useGyroPush]; // 介面點選時就會呼叫陀螺儀
}

- (void)viewDidDisappear:(BOOL)animated {
    // 該介面消失時一定要停止,不然會一直呼叫消耗記憶體
    [self.motionManager stopDeviceMotionUpdates]; // 停止所有的裝置
//    [self.motionManager stopAccelerometerUpdates]; // 加速度計
//    [self.motionManager stopMagnetometerUpdates]; // 磁力計
//    [self.motionManager stopGyroUpdates]; // 陀螺
}

- (void)useGyroPush{
    //初始化全域性管理物件
    CMMotionManager *manager = [[CMMotionManager alloc] init];
    self.motionManager = manager;
    
    if ([self.motionManager isDeviceMotionAvailable]) {
        manager.deviceMotionUpdateInterval = 1;
        [self.motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue]
                                                withHandler:^(CMDeviceMotion * _Nullable motion,
                                                              NSError * _Nullable error) {
            
            // Gravity 獲取手機的重力值在各個方向上的分量,根據這個就可以獲得手機的空間位置,傾斜角度等
            double gravityX = motion.gravity.x;
            double gravityY = motion.gravity.y;
            double gravityZ = motion.gravity.z;
            
            // 獲取手機的傾斜角度(zTheta是手機與水平面的夾角, xyTheta是手機繞自身旋轉的角度):
            double zTheta = atan2(gravityZ,sqrtf(gravityX * gravityX + gravityY * gravityY)) / M_PI * 180.0;
            double xyTheta = atan2(gravityX, gravityY) / M_PI * 180.0;
            
            NSLog(@"手機與水平面的夾角 --- %.4f, 手機繞自身旋轉的角度為 --- %.4f", zTheta, xyTheta);
        }];
    }
}

@end

通過我們上面 block 回撥的結果,我們可以精確的定位 iPhone 與水平面的夾角 以及 iPhone 繞自身旋轉的角度。這樣無論你的手機如何傾斜翻轉,我們都能拿到它當前的一個狀態。多次測試之後,就能獲取到你想要設定的一個狀態區間了。