ForceTouchGestureRecognizer.swift 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. import UIKit.UIGestureRecognizerSubclass
  2. import RxSwift
  3. import RxCocoa
  4. @available(iOS 9.0, *)
  5. public class ForceTouchGestureRecognizer: UIGestureRecognizer {
  6. public var numberOfTouchesRequired: Int = 1
  7. public private(set) var force: CGFloat = 0
  8. public private(set) var maximumPossibleForce: CGFloat = 0
  9. public var fractionCompleted: CGFloat {
  10. guard maximumPossibleForce > 0 else {
  11. return 0
  12. }
  13. return force / maximumPossibleForce
  14. }
  15. public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
  16. super.touchesBegan(touches, with: event)
  17. state = .began
  18. setForce(for: touches)
  19. }
  20. public override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
  21. super.touchesMoved(touches, with: event)
  22. state = .changed
  23. setForce(for: touches)
  24. }
  25. public override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
  26. super.touchesEnded(touches, with: event)
  27. state = .ended
  28. setForce(for: touches)
  29. }
  30. private func setForce(for touches: Set<UITouch>) {
  31. guard touches.count == numberOfTouchesRequired, let touch = touches.first else {
  32. state = .failed
  33. return
  34. }
  35. force = Array(touches)[1...]
  36. .lazy
  37. .map { $0.force}
  38. .reduce(touch.force, +) / CGFloat(touches.count)
  39. maximumPossibleForce = Array(touches)[1...]
  40. .lazy
  41. .map { $0.maximumPossibleForce}
  42. .reduce(touch.maximumPossibleForce, +) / CGFloat(touches.count)
  43. }
  44. }
  45. @available(iOS 9.0, *)
  46. public typealias ForceTouchConfiguration = Configuration<ForceTouchGestureRecognizer>
  47. @available(iOS 9.0, *)
  48. public typealias ForceTouchControlEvent = ControlEvent<ForceTouchGestureRecognizer>
  49. @available(iOS 9.0, *)
  50. public typealias ForceTouchObservable = Observable<ForceTouchGestureRecognizer>
  51. @available(iOS 9.0, *)
  52. extension Factory where Gesture == GestureRecognizer {
  53. /**
  54. Returns an `AnyFactory` for `ForceTouchGestureRecognizer`
  55. - parameter configuration: A closure that allows to fully configure the gesture recognizer
  56. */
  57. public static func forceTouch(configuration: ForceTouchConfiguration? = nil) -> AnyFactory {
  58. return make(configuration: configuration).abstracted()
  59. }
  60. }
  61. @available(iOS 9.0, *)
  62. extension Reactive where Base: View {
  63. /**
  64. Returns an observable `ForceTouchGestureRecognizer` events sequence
  65. - parameter configuration: A closure that allows to fully configure the gesture recognizer
  66. */
  67. public func forceTouchGesture(configuration: ForceTouchConfiguration? = nil) -> ForceTouchControlEvent {
  68. return gesture(make(configuration: configuration))
  69. }
  70. }
  71. @available(iOS 9.0, *)
  72. extension ObservableType where Element: ForceTouchGestureRecognizer {
  73. /**
  74. Maps the observable `GestureRecognizer` events sequence to an observable sequence of force values.
  75. */
  76. public func asForce() -> Observable<CGFloat> {
  77. return self.map { $0.force }
  78. }
  79. }