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
- Quick actions
- Peek and pop actions
- Measuring the force of touch
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