这是一款开源应用,它利用 iPhone 6s 的 3D Touch 屏幕来测量出物体和手机的可能最大力值的相对比。用户还可以选择让 3D Touch 来测量其他物体的相对重量,只要它不超过 iPhone 6s 屏幕能够承受的重量即可。
iPhone的屏幕可以同时检测到五个物体的存在,所以从理论上来说,它或许可以同时对比五个物体的重量。如上图是用户的使用测试,他们发现这款应用使用起来没有什么问题。3D Touch 屏幕的压力敏感度超出用户的想象,在这里你能够发现它可以感应到不同程度的力量。
代码如下:
class ViewController: UIViewController
{
let label = UILabel()
var circles = [UITouch: CircleWithLabel]()
override func viewDidLoad()
{
super.viewDidLoad()
view.multipleTouchEnabled = true
label.text = "lay your plums on me."
label.textAlignment = NSTextAlignment.Center
view.addSubview(label)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
{
label.hidden = true
for touch in touches
{
let circle = CircleWithLabel()
circle.drawAtPoint(touch.locationInView(view),
force: touch.force / touch.maximumPossibleForce)
circles[touch] = circle
view.layer.addSublayer(circle)
}
highlightHeaviest()
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?)
{
for touch in touches where circles[touch] != nil
{
let circle = circles[touch]!
circle.drawAtPoint(touch.locationInView(view),
force: touch.force / touch.maximumPossibleForce)
}
highlightHeaviest()
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?)
{
for touch in touches where circles[touch] != nil
{
let circle = circles[touch]!
circles.removeValueForKey(touch)
circle.removeFromSuperlayer()
}
highlightHeaviest()
}
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?)
{
guard let touches = touches else
{
return
}
for touch in touches where circles[touch] != nil
{
let circle = circles[touch]!
circle.removeFromSuperlayer()
}
}
func highlightHeaviest()
{
func getMaxTouch() -> UITouch?
{
return circles.sort({
(a: (UITouch, CircleWithLabel), b: (UITouch, CircleWithLabel)) -> Bool in
return a.0.force > b.0.force
}).first?.0
}
circles.forEach
{
$0.1.isMax = $0.0 == getMaxTouch()
}
}
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask
{
return UIInterfaceOrientationMask.Landscape
}
override func viewDidLayoutSubviews()
{
label.frame = view.bounds
}
}
// -------------
class CircleWithLabel: CAShapeLayer
{
let text = CATextLayer()
override init()
{
super.init()
text.foregroundColor = UIColor.blueColor().CGColor
text.alignmentMode = kCAAlignmentCenter
addSublayer(text)
strokeColor = UIColor.blueColor().CGColor
lineWidth = 5
fillColor = nil
}
override init(layer: AnyObject)
{
super.init(layer: layer)
}
required init?(coder aDecoder: NSCoder)
{
fatalError("init(coder:) has not been implemented")
}
var isMax: Bool = false
{
didSet
{
fillColor = isMax ? UIColor.yellowColor().CGColor : nil
}
}
func drawAtPoint(location: CGPoint, force: CGFloat)
{
let radius = 120 + (force * 120)
path = UIBezierPath(
ovalInRect: CGRect(
origin: location.offset(dx: radius, dy: radius),
size: CGSize(width: radius * 2, height: radius * 2))).CGPath
text.string = String(format: "%.1f%%", force * 100)
text.frame = CGRect(origin: location.offset(dx: 75, dy: -radius), size: CGSize(width: 150, height: 40))
}
}
// -------------
extension CGPoint
{
func offset(dx dx: CGFloat, dy: CGFloat) -> CGPoint
{
return CGPoint(x: self.x - dx, y: self.y - dy)
}
}