当用户将 iphone 举到脸上时,我想得到通知。就像siri一样。是否可以?
添加更具体的要求:当用户将手机靠近耳朵时,我想使屏幕变暗。我知道接近传感器可以实现这一点。但令人讨厌的是,当用户在传感器上移动手指时,屏幕会不时变暗。所以我想知道如何避免这种情况,只在用户举起 iphone 说话时才使屏幕变暗?
请参阅UIDevice 类参考中的使用接近传感器。那么你:
启用它:
UIDevice *device = [UIDevice currentDevice];
device.proximityMonitoringEnabled = YES;
检查是否启用成功;如果成功,请观察UIDeviceProximityStateDidChangeNotification
通知;如果没有,您的设备可能无法:
if (device.proximityMonitoringEnabled)
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleProximityChange:)
name:UIDeviceProximityStateDidChangeNotification
object:nil];
}
else
{
// device not capable
}
并编写您的选择器:
- (void)handleProximityChange:(NSNotification *)notification
{
NSLog(@"%s proximityState=%d", __FUNCTION__, [[UIDevice currentDevice] proximityState]);
}
为了检测用户是否将手机举到了脸上,我可能会将接近传感器与手机结合起来,CMMotionManager
然后查看gravity
属性,看看他们是否几乎垂直地拿着手机。因此,定义一些类属性:
@property (nonatomic, strong) CMMotionManager *motionManager;
@property (nonatomic, strong) NSOperationQueue *deviceQueue;
然后您可以启动CMMotionManager
,查看设备是否保持在垂直位置:
self.deviceQueue = [[NSOperationQueue alloc] init];
self.motionManager = [[CMMotionManager alloc] init];
self.motionManager.deviceMotionUpdateInterval = 5.0 / 60.0;
UIDevice *device = [UIDevice currentDevice];
[self.motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXArbitraryZVertical
toQueue:self.deviceQueue
withHandler:^(CMDeviceMotion *motion, NSError *error)
{
BOOL vertical = (motion.gravity.z > -0.4 && motion.gravity.z < 0.4 & motion.gravity.y < -0.7);
if ((vertical && !device.proximityMonitoringEnabled) || (!vertical && device.proximityMonitoringEnabled))
{
device.proximityMonitoringEnabled = vertical;
}
}];
这些gravity
阈值是否有意义有点主观。您还可以查看其他加速度计数据(例如,他们是否举起物体),而不仅仅是查看手机是否大致垂直握持。似乎有很多方法可以给猫剥皮。
我知道这很旧,但我稍微简化了逻辑并在 Swift 中创建了一个包装类。
class DeviceRaisedToEarListener: NSObject {
private let deviceQueue = NSOperationQueue()
private let motionManager = CMMotionManager()
private var vertical: Bool = false
private(set) var isRaisedToEar: Bool = false {
didSet {
if oldValue != self.isRaisedToEar {
self.stateChanged?(isRaisedToEar: self.isRaisedToEar)
}
}
}
var stateChanged:((isRaisedToEar: Bool)->())? = nil
override init() {
super.init()
self.setupMotionManager()
}
private func setupMotionManager() {
self.motionManager.deviceMotionUpdateInterval = 5.0 / 60.0
let device = UIDevice.currentDevice()
// Only listen for proximity changes if the device is held vertically
self.motionManager.startDeviceMotionUpdatesUsingReferenceFrame(CMAttitudeReferenceFrame.XArbitraryZVertical, toQueue: self.deviceQueue) { (motion, error) in
self.vertical = (motion.gravity.z > -0.4 && motion.gravity.z < 0.4 && motion.gravity.y < -0.7)
}
}
func startListening() {
UIDevice.currentDevice().proximityMonitoringEnabled = true
NSNotificationCenter.defaultCenter().addObserver(self, selector: "handleProximityChange:", name: UIDeviceProximityStateDidChangeNotification, object: nil)
}
func stopListening() {
UIDevice.currentDevice().proximityMonitoringEnabled = false
NSNotificationCenter.defaultCenter().removeObserver(self)
}
func handleProximityChange(notification: NSNotification) {
self.isRaisedToEar = UIDevice.currentDevice().proximityState && self.vertical
}
deinit {
self.stopListening()
}
}
// How to use:
private func setupRaiseListener() {
self.deviceListener.stateChanged = { [weak self] isRaisedToEar in
println("is raised? \(isRaisedToEar)")
}
self.deviceListener.startListening()
}