本节书摘来自异步社区《iOS 6高级开发手册(第4版)》一书中的第1章,第1.10节秘诀:Core Motion基础,作者 【美】Erica Sadun,更多章节内容可以访问云栖社区“异步社区”公众号查看
1.10 秘诀:Core Motion基础
iOS 6高级开发手册(第4版)
Core Motion框架集中了运动数据处理。该框架是在iOS 4 SDK中引入的,用于取代你刚才阅读到的直接加速计访问。它提供了对3个关键的机载传感器的集中式监测。这些传感器由陀螺仪、磁力计和加速计组成,其中陀螺仪用于测量设备的旋转,磁力计提供了一种测量罗盘方位的方式,加速计用于检测沿着3根轴的重力变化。第四个入口点称为设备移动(device motion),它把全部3种传感器都结合进单个监测系统中。
Core Motion使用来自这些传感器原始值创建可度的测量结果,主要表现为力向量的形式。可测量的项包括以下属性。
设备姿势(attitude):设备相对于某个参照画面的方向。姿势被表示为摇晃、前倾和左右摇摆的角度,它们都以弧度为单位。
旋转速率(rotationRate):设备围绕它的3根轴中的每一根轴旋转的速率。旋转包括x、y和z角速度值,它们以弧度/秒为单位。
重力(gravity):设备当前的加速度向量,由正常的重力场提供。重力的单位是g's,分别沿着x、y和z轴来测量。每个单位代表由地球提供的标准重力加速度(9.8米/秒2)。
用户加速度(userAcceleration):用户提供的加速度向量。像重力一样,用户加速度的单位也是g's,分别沿着x、y和z轴来测量。当把它们加到一起时,用户向量和重力向量代表给设备提供的总加速度。
磁场(magneticField):代表设备邻近区域里的总磁场的向量。磁场是沿着x、y和z轴以微特斯拉(microtesla)为单位测量的。还提供了校准精度,通知应用程序有关磁场测量的质量。
1.10.1 测试传感器
正如在本章前面所学到的,可以使用应用程序的Info.plist文件要求使用或排除机载传感器。也可以在应用程序内测试每种可能的Core Motion支持:
if (motionManager.gyroAvailable)
[motionManager startGyroUpdates];
if (motionManager.magnetometerAvailable)
[motionManager startMagnetometerUpdates];
if (motionManager.accelerometerAvailable)
[motionManager startAccelerometerUpdates];
if (motionManager.deviceMotionAvailable)
[motionManager startDeviceMotionUpdates];
开始更新不会产生像使用UIAccelerometer时遇到的委托回调机制。作为替代,你将负责轮询每个值,或者可以使用基于块的更新机制,执行在每次更新时提供的一个块(例如,startAccelerometerUpdatesToQueue:withHandler:)。
1.10.2 处理程序块
秘诀1-6修改了秘诀1-4,以便使用Core Motion。把加速度回调移入一个处理程序块中,并从数据的加速度属性中读取x和y值。否则,代码将保持不变。在这里,将看到Core Motion的一些基本的方面:创建一个新的运动管理器,它用于测试加速计可用性。然后,它将使用一个新的操作队列开始更新,该队列在应用程序运行期间将持续存在。
establishMotionManager和shutDownMotionManager方法使应用程序能够根据需要启动和关闭运动管理器。这些方法是在应用程序变成活动时和挂起时从应用程序委托内调用的:
- (void) applicationWillResignActive:(UIApplication *)application
{
[tbvc shutDownMotionManager];
}
- (void) applicationDidBecomeActive:(UIApplication *)application
{
[tbvc establishMotionManager];
}
这些方法提供了一种干净的方式,用于关闭和恢复运动服务,以响应当前的应用程序状态。
秘诀1-6 基本的Core Motion
@implementation TestBedViewController
- (void) tick
{
butterfly.transform = CGAffineTransformIdentity;
// Move the butterfly according to the current velocity vector
CGRect rect = CGRectOffset(butterfly.frame, xvelocity, 0.0f);
if (CGRectContainsRect(self.view.bounds, rect))
butterfly.frame = rect;
rect = CGRectOffset(butterfly.frame, 0.0f, yvelocity);
if (CGRectContainsRect(self.view.bounds, rect))
butterfly.frame = rect;
butterfly.transform =
CGAffineTransformMakeRotation(mostRecentAngle + M_PI_2);
}
- (void) shutDownMotionManager
{
NSLog(@"Shutting down motion manager");
[motionManager stopAccelerometerUpdates];
motionManager = nil;
[timer invalidate];
timer = nil;
}
- (void) establishMotionManager
{
if (motionManager)
[self shutDownMotionManager];
NSLog(@"Establishing motion manager");
// Establish the motion manager
motionManager = [[CMMotionManager alloc] init];
if (motionManager.accelerometerAvailable)
[motionManager
startAccelerometerUpdatesToQueue:
[[NSOperationQueue alloc] init]
withHandler:^(CMAccelerometerData *data, NSError *error)
{
// Extract the acceleration components
float xx = -data.acceleration.x;
float yy = data.acceleration.y;
mostRecentAngle = atan2(yy, xx);
// Has the direction changed?
float accelDirX = SIGN(xvelocity) * -1.0f;
float newDirX = SIGN(xx);
float accelDirY = SIGN(yvelocity) * -1.0f;
float newDirY = SIGN(yy);
// Accelerate. To increase viscosity,
// lower the additive value
if (accelDirX == newDirX)
xaccel = (abs(xaccel) + 0.85f) * SIGN(xaccel);
if (accelDirY == newDirY)
yaccel = (abs(yaccel) + 0.85f) * SIGN(yaccel);
// Apply acceleration changes to the current velocity
xvelocity = -xaccel * xx;
yvelocity = -yaccel * yy;
}];
// Start the physics timer
timer = [NSTimer scheduledTimerWithTimeInterval: 0.03f
target: self selector: @selector(tick)
userInfo: nil repeats: YES];
}
- (void) initButterfly
{
CGSize size;
// Load the animation cells
NSMutableArray *butterflies = [NSMutableArray array];
for (int i = 1; i <= 17; i++)
{
NSString *fileName =
[NSString stringWithFormat:@"bf_%d.png", i];
UIImage *image = [UIImage imageNamed:fileName];
size = image.size;
[butterflies addObject:image];
}
// Begin the animation
butterfly = [[UIImageView alloc]
initWithFrame:(CGRect){.size=size}];
[butterfly setAnimationImages:butterflies];
butterfly.animationDuration = 0.75f;
[butterfly startAnimating];
// Set the butterfly's initial speed and acceleration
xaccel = 2.0f;
yaccel = 2.0f;
xvelocity = 0.0f;
yvelocity = 0.0f;
// Add the butterfly
butterfly.center = RECTCENTER(self.view.bounds);
[self.view addSubview:butterfly];
}
- (void) loadView
{
[super loadView];
self.view.backgroundColor = [UIColor whiteColor];
[self initButterfly];
}
@end