本节书摘来自异步社区《iOS 6高级开发手册(第4版)》一书中的第1章,第1.3节秘诀:检查设备接近度和电池状态,作者 【美】Erica Sadun,更多章节内容可以访问云栖社区“异步社区”公众号查看
1.3 秘诀:检查设备接近度和电池状态
iOS 6高级开发手册(第4版)
UIDevice类提供了一些API,使你能够跟踪设备的特征,包括电池的状态和接近度传感器。秘诀1-1演示了如何启用和查询对这两种技术的监测。它们二者都以通知的形式提供更新,可以订阅它们,以便在有重要的更新时通知你的应用程序。
1.3.1 启用和禁用接近度传感器
接近度在此时是一个特定于iPhone的特性。iPod Touch和iPad没有提供接近度传感器。除非具有相对身体部位握持iPhone的某个迫切的理由(或者反之亦然),否则使用接近度传感器获益甚少。
当启用接近度传感器时,它具有一项主要的任务。它会检测正前方是否有较大的物体。如果是,它将会关闭屏幕,并发送一个普通的通知。把阻挡的物体移开,将会再次打开屏幕。在你打电话时,这可以防止耳朵接触屏幕导致按键或者拨号。一些设计不佳的保护性外壳将会阻止iPhone的接近度传感器正确地工作。
Siri使用了这个特性,当把手机抬高到耳朵附近时,它会记录你的询问,发送它以进行解释。Siri的语音接口在工作时不依赖于可视化的GUI。
秘诀1-1还演示了在iPhone上如何处理接近度传感。它的代码使用UIDevice类切换接近度监测,并且订阅UIDeviceProximityStateDidChangeNotification以捕获状态改变。两种状态是开和关。当UIDevice proximityState属性返回YES时,就激活了接近度传感器。
1.3.2 监测电池状态
可以以编程方式跟踪电池和设备状态。这些API使你能够知道电池充电的程度,以及设备是否插入到了充电电源中。电池电量是一个范围在1.0(完全充电)~0.0(完全放电)之间的浮点值。它提供了一个近似的放电水平,在执行将给设备施加罕见重负的操作之前,可以查询它。
例如,在用户执行一系列大型的数学计算之前,你可能想提醒它,并且建议插入电源。可以通过下面这个UIDevice调用获取电池电量,返回的值是以5%的增量产生的:
NSLog(@" level: %0.2f%",
[UIDevice currentDevice].batteryLevel * 100);
充电状态具有4个可能的值:正在充电(即连接到电源)、充满、拔掉电源插头和笼统的“未知状态”。可以使用UIDevice batteryState属性取回这些状态:
NSArray *stateArray = @[
@"Battery state is unknown",
@"Battery is not plugged into a charging source",
@"Battery is charging",
@"Battery state is full"];
NSLog(@" state: %@",
stateArray[[UIDevice currentDevice].batteryState]);
不要把这些选择视作持久的状态。可代之以把它们视作对设备上实际发生的事情的短暂反应。它们不是标志,不能用“或”把它们连接起来构成一般性的电池描述。相反,这些值反映了最近的状态改变。
可以通过响应电池状态改变的通知,轻松地监测状态改变。这样,就可以捕获瞬时事件,比如当电池最终充满电时,当用户插入电源充电时,以及当用户断开与电源的连接时。
要开始监测,可以把batteryMonitoringEnabled属性设置为YES。在监测期间,当电池状态或电量改变时,UIDevice类将产生通知。秘诀1-1订阅了这两种通知。请注意:也可以直接检查这些值,而不必等待通知。Apple对于电量改变更新的频率没有提供任何保证,但是可以通过测试这个秘诀来断定,它们是以相当规则的方式发生的。
秘诀1-1 监测接近度和电池
// View the current battery level and state
- (void) peekAtBatteryState
{
NSArray *stateArray = [NSArray arrayWithObjects:
@"Battery state is unknown",
@"Battery is not plugged into a charging source",
@"Battery is charging",
@"Battery state is full", nil];
NSString *status = [NSString stringWithFormat:
@"Battery state: %@, Battery level: %0.2f%%",
[stateArray objectAtIndex:[UIDevice currentDevice].batteryState],
[UIDevice currentDevice].batteryLevel * 100];
NSLog(@"%@", status);
}
// Show whether proximity is being monitored
- (void) updateTitle
{
self.title = [NSString stringWithFormat:@"Proximity %@",
[UIDevice currentDevice].proximityMonitoringEnabled ? @"On" : @"Off"];
}
// Toggle proximity monitoring off and on
- (void) toggle: (id) sender
{
// Determine the current proximity monitoring and toggle it
BOOL isEnabled = [UIDevice currentDevice].proximityMonitoringEnabled;
[UIDevice currentDevice].proximityMonitoringEnabled = !isEnabled;
[self updateTitle];
}
- (void) loadView
{
[super loadView];
// Enable toggling and initialize title
self.navigationItem.rightBarButtonItem =
BARBUTTON(@"Toggle", @selector(toggle:));
[self updateTitle];
// Add proximity state checker
[[NSNotificationCenter defaultCenter]
addObserverForName:UIDeviceProximityStateDidChangeNotification
object:nil queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *notification) {
// Sensor has triggered either on or off
NSLog(@"The proximity sensor %@",
[UIDevice currentDevice].proximityState ?
@"will now blank the screen" : @"will now restore the screen");
}];
// Enable battery monitoring
[[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];
// Add observers for battery state and level changes
[[NSNotificationCenter defaultCenter]
addObserverForName:UIDeviceBatteryStateDidChangeNotification
object:nil queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *notification) {
// State has changed
NSLog(@" Change");
[self peekAtBatteryState];
}];
[[NSNotificationCenter defaultCenter]
addObserverForName:UIDeviceBatteryLevelDidChangeNotification
object:nil queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *notification) {
// Level has changed
NSLog(@" Level Change");
[self peekAtBatteryState];
}];
}
获取这个秘诀的代码
要查找这个秘诀的完整示例项目,可以浏览https://github.com/erica/iOS-6-Advanced-Cookbook,并进入第1章的文件夹。
1.3.3 检测Retina支持
近年来,Apple在其旗舰设备上引入了Retina显示屏。根据Apple的说法,它的像素密度非常高,足以使人眼无法区分单独的像素。带有更高分辨率的艺术的应用程序可以利用这种改进的显示质量。
UIScreen类提供了一种容易的方式,用于检查当前设备是否提供了内置的Retina显示屏。检查屏幕的scale属性,它提供了从逻辑坐标空间(磅,大约是1/160英寸)转换为设备坐标空间(像素)的转换因子。对于标准显示屏,转换因子是1.0,因此1点对应于1像素。对于Retina显示屏,它是2.0(4像素/磅):
``
- (BOOL) hasRetinaDisplay
{
return ([UIScreen mainScreen].scale == 2.0f);
}
UIScreen类还提供了两个有用的显示屏尺寸属性。bounds返回屏幕的边界矩形,以磅为单位。无论屏幕上有任何元素(比如状态栏、导航栏或标签栏),这都会提供屏幕的完全尺寸。