本文对Motion Events的机制进行讲解。
iOS系统的Events类型分为以下几种:Multitouch events, Accelerometer events, Remote control events。
Motion Events
Motion Events包括设备的定位(Location)、朝向(Orientation)和移动(Movement)。通过处理这些Events,可以对App进行更精妙的处理。加速器(Accelerometer)和陀螺仪(gyroscope)数据可以用于检测设备的倾斜(tilting)、旋转(rotation)和摇晃(shaking)。
加速器(Accelerometer)实际上是由三个不同维度的加速度构成的,分别对应x, y, z轴,每个加速器测量该维度随着时间沿着线性的速度变化。把这三个组合在一起,就可以取到设备的朝向以及任意方向上的移动。陀螺仪(gyroscope)是测量这三个方向上的旋转速度。
Getting the Current Device Orientation with UIDevice
如果只需要获取设备的朝向,而并不需要获取到精准的向量信息,使用UIDevice类即可。使用方式如下:
1 | -(void) viewDidLoad { |
这里,为了防止硬件处于省电关闭状态,需要先调用一下beginGeneratingDeviceOrientationNotifications方法,在不需要时,调用endGeneratingDeviceOrientationNotifications方法。
Detecting Shake-Motion Events with UIEvent
当用户摇晃设备时,iOS系统计算加速器的加速度,一旦达到阈值,则生成一个UIEvent,并将其传递给App处理。Motion Events只会在开始和结束时候,传递给App,不像Touch Events是连续的。Motion Events只包含了一种事件类型UIEventTypeMotion,和子事件类型UIEventSubtypeMotionShake,以及时间戳Timestamp。
举例如下:
1 | - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event |
Setting and Checking Required Hardware Capabilities for Motion Events
如果App是严重依赖于设备的加速器或者陀螺仪的数据,而对于那些不支持的设备,App可能并不能起到作用,则App应该在info.plist中加入以下字段:
1 | <key>UIRequiredDeviceCapabilities</key> |
iOS系统会根据该字段判断是否在必要时运行App,且App Store也会通过该字段确保用户的设备是有上述硬件的。
如果App并不是严重依赖该硬件,可以在运行时判断硬件是否支持,下面章节会介绍。
Capturing Device Movement with Core Motion
如果需要精确的加速器和陀螺仪数据,可以使用CoreMotion.framework。CoreMotion与UIKit不同,它与UIEvent无关,也不会使用响应链,而是简单的分发Core Motion Events.
Core Motion Events包含三种数据,分别是:
- CMAccelerometerData:包含每个轴方向的移动加速度;
- CMGyroData:包含三个轴方向的旋转加速度;
- CMDeviceMotion:包含一些不同的测量数据,例如海拔以及其他一些由旋转加速度和移动加速度构成的数据。
以上的数据类,都继承自CMLogItem,该类包含了时间戳,可以用于比较Event的前后顺序。
这里用到的类是CMMotionManager,每个App都必须只能创造一个该类的实例,否则会导致数据的接收收到影响。例如,检查硬件是否支持:
1 | _motionManager = [CMMotionManager new]; |
CMMotionManager有两种方式可以获取到数据,分别是:
- Pull:调用CMMotionManager的startUpdate方法,并且通过计时器,去获取CMMotionManager的属性值,来主动获取数据;
- Push:设置CMMotionManager的updateInterval属性,来设置间隔时间,并调用CMMotionManager的startUpdate的block方法,来被动获取数据。
显然,Push方法更好一些,下面是例子:
1 | _motionManager = [CMMotionManager new]; |
注意,在不需要数据时,要调用stopUpdate,这样可以关闭传感器,以节省设备电量。
(1) 间隔时间设置
下面是获取数据的推荐频率:
- 10-20(Hz):用于判断设备朝向;
- 30-60(Hz):游戏或者其他App用于获取实时的用户输入;
- 70-100(Hz):需要高频Motion的App,例如检测用户点击屏幕或者快速摇晃。
(2) 三维轴朝向
加速器的三维轴朝向:
陀螺仪的三维轴朝向:
(3) Motion Data
CMDeviceMotion同时包含了加速器和陀螺仪的数据,另外,对重力加速度(Gravity)与用户的加速度做了区分。
CMDeviceMotion的attitude属性,包含了以下属性:
- 等式(Quaternion)
- 旋转矩阵(Rotation Matrix)
- 欧拉角(Euler Angles):x轴转过角度(Pitch)、y轴转过角度(Roll)、z轴转过角度(Yaw)
如果没有设置,则CMDeviceMotion的参考轴面是重力轴面,即:
CMDeviceMotion通过这个参考轴面来与当前轴面进行比较,从而得出设备的旋转信息,如果需要,可以修改参考轴面,例如,下面是以Pitch开始的轴面为参考轴面,而不是以重力轴面:
1 | -(void) startPitch { |
Applications
利用Motion Events可以做很多有意思的事情,例如:
保持图片永远水平:
1 | UIImageView *iv = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"me.jpg"]]; |
倾斜可以自动滑动列表:
1 | - (void)viewDidLoad { |