Есть ли способ отслеживать движение пользователя на iphone, например, функцию «поднять, чтобы говорить»?

Я хочу получать уведомления, когда пользователь подносит iphone к лицу. Так же, как это делает Сири. Является ли это возможным?

Добавьте более конкретное требование: я хочу затемнить экран, когда пользователь подносит телефон к уху. Я знаю, что для этого можно включить датчик приближения. Но раздражает то, что экран время от времени затемняется, когда пользователь проводит пальцем по датчику. Поэтому мне интересно, как избежать этого случая и затемнять экран только тогда, когда пользователь поднимает iphone, чтобы говорить?


person fantaxy    schedule 19.03.2013    source источник


Ответы (2)


См. Использование Датчик приближения в Справочнике по классам 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 пороговые значения, это немного субъективно. Вы также можете вместо того, чтобы просто смотреть, держится ли телефон примерно вертикально, посмотреть на другие данные акселерометра (например, подняли ли они объект или нет). Кажется, есть много способов освежевать кошку.

person Rob    schedule 19.03.2013
comment
Предположительно, приложение должно быть на переднем плане, чтобы это работало? - person mttrb; 19.03.2013
comment
@fantaxy Вы можете использовать Core Motion для определения ориентации устройства. Или вы можете посмотреть на данные акселерометра, чтобы выяснить, был ли поднят телефон или нет. Во всяком случае, я обновил свой ответ чем-то, что выполняет мониторинг близости, только если телефон находится примерно в вертикальном положении. - person Rob; 19.03.2013
comment
@mttrb да, я полагаю, что приложение должно быть на переднем плане. - person Rob; 19.03.2013
comment
@JitendraDeore Я не понимаю тебя. Вы спрашиваете, как просто использовать датчик приближения? - person Rob; 23.08.2013
comment
да, я использовал этот код, но моя проблема в том, что когда пользователь двигает рукой, я хочу получить состояние или любое значение. пожалуйста, помогите мне в этом... - person Jitendra; 23.08.2013
comment
@JitendraDeore Вы должны сформулировать, что вы пытаетесь сделать, что вы пробовали до сих пор, и объяснить, например, почему подход с датчиком приближения не работает. Это будет достаточно долго, поэтому я предлагаю вам не публиковать это в комментарии здесь, а вместо этого задавать совершенно новый вопрос самостоятельно. И, без обид, просто сказать, что вы хотите знать, когда пользователь двигает рукой, недостаточно ясно. Это может означать что угодно. Расскажите нам, чего именно вы хотите и почему датчика приближения (или чего-то еще) не хватило. - person Rob; 23.08.2013
comment
@Rob, я разместил новый вопрос в stackoverflow, пожалуйста, проверьте его, пожалуйста, помогите мне .... чтобы сделать это - person Jitendra; 23.08.2013
comment
Есть ли способ сделать это для приложений, работающих в фоновом режиме? - person nanospeck; 16.10.2014
comment
@nanospeck Нет, Apple поддерживает фоновую работу только в довольно узком кругу обстоятельств (например, чтобы позволить вам выполнить какую-то задачу конечной длины (не более 3 минут) или определенные типы приложений, такие как навигация, аудиоплеер, VOIP и т. д. .). Дополнительные сведения см. в Руководстве по программированию приложений. для iOS: фоновое выполнение. - person Rob; 17.10.2014

Я знаю, что это старо, но я немного упростил логику и сделал класс-оболочку в 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()
}
person Mike Sprague    schedule 03.11.2015