Upgrade to Pro — share decks privately, control downloads, hide ads and more …

An introduction to 3D Touch for Swift developers

An introduction to 3D Touch for Swift developers

My Swift London talk of October 19, 2015 discussing 3D Touch for Swift

simon gladman

October 19, 2015
Tweet

More Decks by simon gladman

Other Decks in Programming

Transcript

  1. 3D TOUCH An introduction to 3D Touch for Swift developers

    Simon Gladman for Swift London / October 2015
  2. 3D TOUCH FOR USERS • Peek • Preview Actions •

    Pop • Quick Actions • Pressure Sensitivity
  3. 3D TOUCH FOR DEVS • Simple API • Check device

    supports 3D Touch traitCollection.forceTouchCapability == UIForceTouchCapability.Available
  4. • Simple API • Getting force value override func touchesBegan(touches:

    Set<UITouch>, withEvent event: UIEvent?) { guard let touch = touches.first else { return } let normalisedForce = touch.force / touch.maximumPossibleForce print(normalisedForce) }
  5. • Simple API • Implementing peek and pop registerForPreviewingWithDelegate(delegate, sourceView:

    sourceView) • sourceView reacts to deep press • delegate must implement UIViewControllerPreviewingDelegate
  6. • Peeking & Popping with Previewing Delegate • Protocol contains

    func previewingContext(previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController?
  7. • Peeking & Popping with Previewing Delegate • Protocol contains

    func previewingContext(previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? func previewingContext(previewingContext: UIViewControllerPreviewing, commitViewController viewControllerToCommit: UIViewController)
  8. 3D TOUCH: PEEKING • Peeking - a deep press func

    previewingContext(previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController?
  9. • Peeking let hsl: HSL unowned let delegate: UIViewControllerPreviewingDelegate required

    init(hsl: HSL, delegate: UIViewControllerPreviewingDelegate) { self.hsl = hsl self.delegate = delegate super.init(nibName: nil, bundle: nil) let color = UIColor(hue: hsl.hue, saturation: hsl.saturation, brightness: hsl.lightness, alpha: 1) label.text = "Your color: \(color.getHex())" label.textAlignment = NSTextAlignment.Center smallSwatch.backgroundColor = color }
  10. 3D TOUCH: PREVIEW ACTIONS • Preview Actions • The previewing

    delegate simply needs to implement previewActions()
  11. • Preview Actions enum ColorPresets: String { case Red, Green,

    Blue } var previewActions: [UIPreviewActionItem] { return [ColorPresets.Red, ColorPresets.Green, ColorPresets.Blue].map { UIPreviewAction(title: $0.rawValue, style: UIPreviewActionStyle.Default, handler: { (previewAction, viewController) in (viewController as? PeekViewController)?.updateColor(previewAction) }) } }
  12. • Preview Actions func updateColor(previewAction: UIPreviewActionItem) { guard let delegate

    = delegate as? ChromaTouchViewController, preset = ColorPresets(rawValue: previewAction.title) else { return } let hue: CGFloat switch preset { case .Blue: hue = 0.667 case .Green: hue = 0.333 case .Red: hue = 0 } delegate.hsl = HSL(hue: hue, saturation: 1, lightness: 1) }
  13. 3D TOUCH: POPPING • Popping - a deeper press func

    previewingContext(previewingContext: UIViewControllerPreviewing, commitViewController viewControllerToCommit: UIViewController)
  14. 3D TOUCH: PRESSURE SENSITIVITY • Touch gestures have ‘x’ and

    ‘y’ coordinates • Now have a ‘z’ coordinate corresponding to the pressure of the touch
  15. • Override touchesMoved(): override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?)

    { guard let touch = touches.first else { return } let touchLocation = touch.locationInView(self) let force = touch.force let maximumPossibleForce = touch.maximumPossibleForce let normalisedXPosition = touchLocation.x / frame.width let normalisedYPosition = touchLocation.y / frame.height let normalisedZPosition = force / maximumPossibleForce hsl = HSL(hue: normalisedXPosition, saturation: normalisedYPosition, lightness: normalisedZPosition) sendActionsForControlEvents(.ValueChanged) }
  16. GESTURE RECOGNISERS • As an alternative to overriding a control’s

    touch handling methods • By extending UIGestureRecognizer let deepPressGestureRecognizer = DeepPressGestureRecognizer(target: self, action: "deepPressHandler:", threshold: 0.75) button.addGestureRecognizer(deepPressGestureRecognizer)
  17. • Handle user’s actions in gesture recogniser’s touch handlers override

    func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent) { guard let view = view, touch = touches.first where touch.force != 0 && touch.maximumPossibleForce != 0 else { return } if !deepPressed && (touch.force / touch.maximumPossibleForce) >= threshold { state = UIGestureRecognizerState.Began deepPressed = true } else if deepPressed && (touch.force / touch.maximumPossibleForce) < threshold { state = UIGestureRecognizerState.Ended deepPressed = false } }
  18. TOUCH COALESCING • touchesMoved() samples at up to 60 hertz

    • iPhone 6s has a touch sample rate of 120 hertz
  19. TOUCH COALESCING • touchesMoved() samples at up to 60 hertz

    • iPhone 6s has a touch sample rate of 120 hertz • iPad Pro will sample touches at 240 hertz
  20. • The missing touches can be accessed through the event’s

    coalescedTouches override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) { super.touchesMoved(touches, withEvent: event) guard let touch = touches.first, coalescedTouches = event?.coalescedTouchesForTouch(touch) else { return } for coalescedTouch in coalescedTouches { let locationInView = coalescedTouch.locationInView(view) print(locationInView) } }