iOS 3D Touch - Measuring the force of touch (Part 3)

This is the third part of the series of 3 posts on how to use 3D force touch on an iOS. Posts are as follows

Measuring a force of touch in terms of unit could be useful in some cases. For example, you can map the values of user's force into appropriate actions and then execute it. However, this is just a generic idea and I am sure you will have much more innovative ideas in your mind.

Let's start by creating a label which will show the values of applied force.


let forceValueLabel = UILabel()
override func viewDidLoad() {
    super.viewDidLoad()
    forceValueLabel.translatesAutoresizingMaskIntoConstraints = false
    forceValueLabel.textAlignment = .Center
    forceValueLabel.numberOfLines = 0
    forceValueLabel.text = "Force: 0"
    self.view.addSubview(forceValueLabel)        
    let topLayoutGuide = self.topLayoutGuide
        
    let views: [String: AnyObject] = ["informationLabel": informationLabel, "forceValueLabel": forceValueLabel, "topLayoutGuide": topLayoutGuide]
    self.view.addConstraints(NSLayoutConstraint .constraintsWithVisualFormat("H:|-[informationLabel]-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views))
    self.view.addConstraints(NSLayoutConstraint .constraintsWithVisualFormat("H:|-[forceValueLabel]-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views))
    self.view.addConstraints(NSLayoutConstraint .constraintsWithVisualFormat("V:[topLayoutGuide]-[informationLabel]-[forceValueLabel]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views))
}

Next step is to intercept touch and then calculate the force applied. To do so you have to check pre-condition if device has a force touch capability. This could be checked as follows


if traitCollection.forceTouchCapability == .Available {
    print("Device has a force touch capability")
}

We can use the same concept to detect touches and get the value of force applied as follows.


override func touchesMoved(touches: Set, withEvent event: UIEvent?) {
    if let touch = touches.first where traitCollection.forceTouchCapability == .Available {
        let forceTouchInfo = touch.force
        forceValueLabel.text = String(format: "Force: %.2f", forceTouchInfo)
    }
}

Optionally you can override another method touchesEnded to detect the end of touch event.


override func touchesEnded(touches: Set, withEvent event: UIEvent?) {
    if let _ = touches.first where traitCollection.forceTouchCapability == .Available {
        forceValueLabel.text = "Force: 0"
    }
}

As you can see from example project, touch event is very sensitive. Even applying a subtle finger pressure causes value to fluctuate by bigger margin. So if you are planning to map these values to corresponding actions, please be aware that this could cause usability with some users. If you are still planning to integrate into the app, you might want to consider providing user with alternative UI which will map to similar actions

Note: The full project for 3D touch demo is Available on Github