Oscar Apeland Oscar Apeland - 3 months ago 18
iOS Question

How to recognize a screen high-five

I have a client that wants to recognize when an user smacks their screen with their whole hand, like a high-five. I suspect that Apple won't approve this, but let's look away from that.

I though of using a four-finger-tap recognizer, but that doesn't really cover it. The best approach would possibly be to check if the user is covering at least 70% of the screen with their hand, but I don't know how to do that.

Can someone help me out here?

Answer

Sort of solved it. Proximity + accelerometer works good enough. Multitouch doesn't work, as it ignores stuff it doesn't think of as taps.

import UIKit
import CoreMotion
import AVFoundation

class ViewController: UIViewController {
    var lastHighAccelerationEvent:NSDate? {
        didSet {
            checkForHighFive()
        }
    }

    var lastProximityEvent:NSDate? {
        didSet {
            checkForHighFive()
        }
    }

    var lastHighFive:NSDate?


    var manager = CMMotionManager()

    override func viewDidLoad() {
        super.viewDidLoad()

        //Start disabling the screen
        UIDevice.currentDevice().proximityMonitoringEnabled = true
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(proximityChanged), name: UIDeviceProximityStateDidChangeNotification, object: nil)

        //Check for acceloremeter
        manager.startAccelerometerUpdatesToQueue(NSOperationQueue.mainQueue()) { (data, error) in
            let sum = abs(data!.acceleration.y + data!.acceleration.z + data!.acceleration.x)

            if sum > 3 {
                self.lastHighAccelerationEvent = NSDate()
            }
        }

        //Enable multitouch
        self.view.multipleTouchEnabled = true
    }

    func checkForHighFive() {
        if let lastHighFive = lastHighFive where abs(lastHighFive.timeIntervalSinceDate(NSDate())) < 1 {
            print("Time filter")
            return
        }

        guard let lastProximityEvent = lastProximityEvent else {return}
        guard let lastHighAccelerationEvent = lastHighAccelerationEvent else {return}

        if abs(lastProximityEvent.timeIntervalSinceDate(lastHighAccelerationEvent)) < 0.1 {
            lastHighFive = NSDate()
            playBoratHighFive()
        }

    }

    func playBoratHighFive() {
        print("High Five")
        let player = try! AudioPlayer(fileName: "borat.mp3")
        player.play()
    }

    func proximityChanged() {
        if UIDevice.currentDevice().proximityState {
            self.lastProximityEvent = NSDate()
        }
    }
}