版本记录
版本号 | 时间 |
---|---|
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
次,大约67ms
update一次数据,我们看下面输出。
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
那样,以固定的采样率进行采样。
后记
未完,待续~~~