CoreMotion框架(二)—— 利用加速度计获取设备的方向

版本记录

版本号 时间
V1.0 2017.08.05

前言

我们的app很多都需要获取使用者的动作、方向以及其他和方位或者位置有关的参数,在ios中对应的框架就是CoreMotion,而在硬件对应的就是集成的加速计和陀螺仪。这几篇我们就从基础原理理论出发,讲一下相关的知识。关于这个框架的了解感兴趣的可以看这几篇。
1. CoreMotion框架(一)—— 基础理论

功能要求

前面我写过两篇文章关于横竖屏适配的问题,就是根据设备方向等进行适配的。这里我要说另外一种方法,就是利用CoreMotion框架和加速器获取设备的方向进行适配的。


功能实现

使用加速器,ios5是一个分界线。

  • iOS4以前:使用UIAccelerometer,用法非常简单(到了iOS5就已经过期),虽然过期但是现在仍然可以用。
  • iOS4开始:CoreMotion.framework

1. iOS5以前

iOS5以前使用的是类UIAccelerometer,它属于UIKit框架里面的。

1. JJAccelerometerVC.m
#import "JJAccelerometerVC.h"

@interface JJAccelerometerVC () <UIAccelerometerDelegate>

@end

@implementation JJAccelerometerVC

#pragma mark - Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor whiteColor];
    
    UIAccelerometer *acclerometer = [UIAccelerometer sharedAccelerometer];
    acclerometer.updateInterval = 1.0/15;
    acclerometer.delegate = self;
}

#pragma mark - UIAccelerometerDelegate

- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
    UIAccelerationValue x = acceleration.x;
    UIAccelerationValue y = acceleration.y;
    UIAccelerationValue z = acceleration.z;
    
    if (fabs(x) <= fabs(y)) {
        if (y >= 0) {
            NSLog(@"UIDeviceOrientationPortraitUpsideDown");
        }
        else {
            NSLog(@"UIDeviceOrientationPortrait");
        }
    }
    else {
        if (x >= 0) {
            NSLog(@"UIDeviceOrientationLandscapeRight");
        }
        else {
            NSLog(@"UIDeviceOrientationLandscapeLeft");
        }
    }
}

@end

这里,采样频率为1s15次,所以输出的很快。给大家随便粘出来几个输出值。

2017-08-05 18:00:44.555400+0800 JJOC[7804:3020881] UIDeviceOrientationPortrait
2017-08-05 18:00:44.622714+0800 JJOC[7804:3020881] UIDeviceOrientationLandscapeRight
2017-08-05 18:00:44.689951+0800 JJOC[7804:3020881] UIDeviceOrientationPortrait
2017-08-05 18:00:44.757171+0800 JJOC[7804:3020881] UIDeviceOrientationLandscapeRight
2017-08-05 18:00:44.824398+0800 JJOC[7804:3020881] UIDeviceOrientationPortrait
2017-08-05 18:00:44.891813+0800 JJOC[7804:3020881] UIDeviceOrientationPortrait
2017-08-05 18:00:44.958975+0800 JJOC[7804:3020881] UIDeviceOrientationPortrait
2017-08-05 18:00:45.026187+0800 JJOC[7804:3020881] UIDeviceOrientationPortrait

2. iOS5以后

加速计和陀螺仪的值都是通过Core Motion框架访问的,应用程序创建一个CMMotionManager实例,然后通过以下某种模式使用它:

  • 可以在动作发生时执行一些代码。
  • 可以时刻监视一个持续更新的结构,是你随时能够访问到最新的值。

对于数据的获取和处理,也有两种方式,一种是pull,另外一种是push

  • push :实时采集所有数据(时刻监视,采集频率高),这个是框架按照一定的采用频率自动返回的,具体多上时间发update一次,就看你怎么设置了。
  • pull :在有需要的时候,再主动去采集数据(基于事件的动作)。这个就看开发者什么时候调用什么时候就会返回一次,框架不会主动给返回。

ios5以后,我们看下面代码。

push

//push
1. JJGravityVC.m
#import "JJGravityVC.h"
#import <CoreMotion/CoreMotion.h>

@interface JJGravityVC ()

@property (nonatomic, assign) NSTimeInterval updateInterval;
@property (nonatomic, strong) CMMotionManager *motionManager;

@end

@implementation JJGravityVC

#pragma mark - Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor greenColor];
    
    self.updateInterval = 1.0/15.0;
    self.motionManager = [[CMMotionManager alloc] init];
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    if ([self.motionManager isAccelerometerAvailable]) {
        self.motionManager.accelerometerUpdateInterval = self.updateInterval;
        [self.motionManager startAccelerometerUpdatesToQueue:queue withHandler:^(CMAccelerometerData * _Nullable accelerometerData, NSError * _Nullable error) {
            if (error) {
                NSLog(@"%@",error.description);
            }
            else {
                //在这里进行屏幕方向的判断
//                NSLog(@"x = %lf, y = %lf, z = %lf",accelerometerData.acceleration.x, accelerometerData.acceleration.y, accelerometerData.acceleration.z);
                
                CGFloat x = accelerometerData.acceleration.x;
                CGFloat y = accelerometerData.acceleration.y;
                CGFloat z = accelerometerData.acceleration.z;
                
                if (fabs(x) <= fabs(y)) {
                    if (y >= 0) {
                        NSLog(@"UIDeviceOrientationPortraitUpsideDown");
                    }
                    else {
                        NSLog(@"UIDeviceOrientationPortrait");
                    }
                }
                else {
                    if (x >= 0) {
                        NSLog(@"UIDeviceOrientationLandscapeRight");
                    }
                    else {
                        NSLog(@"UIDeviceOrientationLandscapeLeft");
                    }
                }
            }
        }];
    }
    else {
        NSLog(@"The device does not support accelerometer!");
    }
}

- (void)dealloc
{
    self.motionManager = nil;
}

#pragma mark - Object Private Function

//上面的NSLog(@"x = %lf, y = %lf, z = %lf",accelerometerData.acceleration.x, accelerometerData.acceleration.y, accelerometerData.acceleration.z);一直不停止的回调,因此可以在获取想要的结果以后,调用下面这个方法。
- (void)stopAcceleration
{
    if ([self.motionManager isAccelerometerAvailable]) {
        [self.motionManager stopAccelerometerUpdates];
    }
}

@end

这里我采用的是push的方式,系统会自动的回调数据,我设置的采样就是1s采样15次,大约67msupdate一次数据,我们看下面输出。

2017-08-05 15:50:42.527385+0800 JJOC[7766:2999321] UIDeviceOrientationLandscapeLeft
2017-08-05 15:50:42.594454+0800 JJOC[7766:2999274] UIDeviceOrientationLandscapeLeft
2017-08-05 15:50:42.661608+0800 JJOC[7766:2999321] UIDeviceOrientationLandscapeLeft
2017-08-05 15:50:42.728912+0800 JJOC[7766:2999274] UIDeviceOrientationLandscapeLeft
2017-08-05 15:50:42.796129+0800 JJOC[7766:2999321] UIDeviceOrientationLandscapeLeft
2017-08-05 15:50:42.863421+0800 JJOC[7766:2999274] UIDeviceOrientationLandscapeLeft
2017-08-05 15:50:42.930696+0800 JJOC[7766:2999321] UIDeviceOrientationLandscapeLeft
2017-08-05 15:50:42.998406+0800 JJOC[7766:2999274] UIDeviceOrientationLandscapeLeft
2017-08-05 15:50:43.065164+0800 JJOC[7766:2999321] UIDeviceOrientationLandscapeLeft
2017-08-05 15:50:43.132831+0800 JJOC[7766:2999274] UIDeviceOrientationLandscapeLeft
2017-08-05 15:50:43.199666+0800 JJOC[7766:2999321] UIDeviceOrientationLandscapeLeft
2017-08-05 15:50:43.266782+0800 JJOC[7766:2999274] UIDeviceOrientationLandscapeLeft
2017-08-05 15:50:43.334437+0800 JJOC[7766:2999321] UIDeviceOrientationLandscapeLeft
2017-08-05 15:50:43.401540+0800 JJOC[7766:2999274] UIDeviceOrientationLandscapeLeft
2017-08-05 15:50:43.468730+0800 JJOC[7766:2999321] UIDeviceOrientationLandscapeLeft
2017-08-05 15:50:43.536152+0800 JJOC[7766:2999274] UIDeviceOrientationLandscapeLeft
2017-08-05 15:50:43.604181+0800 JJOC[7766:2999321] UIDeviceOrientationLandscapeLeft
2017-08-05 15:50:43.670330+0800 JJOC[7766:2999274] UIDeviceOrientationLandscapeLeft
2017-08-05 15:50:43.737794+0800 JJOC[7766:2999321] UIDeviceOrientationLandscapeLeft
2017-08-05 15:50:43.804924+0800 JJOC[7766:2999274] UIDeviceOrientationLandscapeLeft
2017-08-05 15:50:43.872237+0800 JJOC[7766:2999321] UIDeviceOrientationLandscapeLeft

确实是这样的。

pull

接下来我们看一下pull形式的代码怎么去写,pull其实就是基于事件进行驱动的,有事件需要的才会触发。

//pull
1. JJPullAcceleratorVC.m
#import "JJPullAcceleratorVC.h"
#import <CoreMotion/CoreMotion.h>

@interface JJPullAcceleratorVC ()

@property (nonatomic, strong) CMMotionManager *motionManager;
@property (nonatomic, assign) CMAcceleration acc;

@end

@implementation JJPullAcceleratorVC

#pragma mark - Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor greenColor];

    self.motionManager = [[CMMotionManager alloc] init];
}

- (void)dealloc
{
    self.motionManager = nil;
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    //pull,基于事件进行驱动,有事件才会去调用
    if ([self.motionManager isAccelerometerAvailable]) {
        //开始采用,并获得采样数据
        [self.motionManager startAccelerometerUpdates];
        self.acc = self.motionManager.accelerometerData.acceleration;
        [self startAccelerometer];
    }
}

#pragma mark - Object Private Function

- (void)stopAcceleration
{
    if ([self.motionManager isAccelerometerAvailable]) {
        [self.motionManager stopAccelerometerUpdates];
    }
}

- (void)startAccelerometer
{
    CGFloat x = self.acc.x;
    CGFloat y = self.acc.y;
    CGFloat z = self.acc.z;
    
    if (fabs(x) <= fabs(y)) {
        if (y >= 0) {
            NSLog(@"UIDeviceOrientationPortraitUpsideDown");
        }
        else {
            NSLog(@"UIDeviceOrientationPortrait");
        }
    }
    else {
        if (x >= 0) {
            NSLog(@"UIDeviceOrientationLandscapeRight");
        }
        else {
            NSLog(@"UIDeviceOrientationLandscapeLeft");
        }
    }
}

@end

下面看一下输出结果

2017-08-05 16:53:12.998816+0800 JJOC[7796:3011684] UIDeviceOrientationLandscapeRight
2017-08-05 16:53:13.201374+0800 JJOC[7796:3011684] UIDeviceOrientationLandscapeRight
2017-08-05 16:53:13.385063+0800 JJOC[7796:3011684] UIDeviceOrientationLandscapeRight
2017-08-05 16:53:13.568807+0800 JJOC[7796:3011684] UIDeviceOrientationLandscapeRight
2017-08-05 16:53:14.849985+0800 JJOC[7796:3011684] UIDeviceOrientationPortraitUpsideDown
2017-08-05 16:53:15.016851+0800 JJOC[7796:3011684] UIDeviceOrientationPortraitUpsideDown
2017-08-05 16:53:15.217770+0800 JJOC[7796:3011684] UIDeviceOrientationPortraitUpsideDown
2017-08-05 16:53:15.367570+0800 JJOC[7796:3011684] UIDeviceOrientationPortraitUpsideDown
2017-08-05 16:53:15.516851+0800 JJOC[7796:3011684] UIDeviceOrientationPortraitUpsideDown

我这里是点击一下屏幕就采样一次,不会像push那样,以固定的采样率进行采样。

后记

未完,待续~~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容