// // ForceTouchGestureRecognizer.m // TouchFlow // // Created by Dana Buehre on 4/26/19. // Copyright © 2019 CreatureCoding. All rights reserved. // #import "CSForceTouchGestureRecognizer.h" #import #import @implementation CSForceTouchGestureRecognizer { CGFloat _maximumForce; BOOL _recognized; } #pragma mark Initialization - (instancetype)init { if ((self = [super initWithTarget:nil action:nil])) { [self _applyDefaults]; } return self; } - (instancetype)initWithTarget:(id)target action:(SEL)action { if ((self = [super initWithTarget:target action:action])) { [self _applyDefaults]; } return self; } #pragma mark UIResponder overrides - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesBegan:touches withEvent:event]; [self triggerWithState:UIGestureRecognizerStateBegan touches:touches]; } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesMoved:touches withEvent:event]; [self triggerWithState:UIGestureRecognizerStateBegan touches:touches]; } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesEnded:touches withEvent:event]; [self triggerWithState:UIGestureRecognizerStateBegan touches:touches]; } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesCancelled:touches withEvent:event]; [self triggerWithState:UIGestureRecognizerStateBegan touches:touches]; } #pragma mark UIGestureRecogniser overrides // prevent blocking other gestures - (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer { return NO; } // reset values when the gesture resets - (void)reset { [super reset]; _force = 0; _recognized = NO; } #pragma mark Implementation // determine the force of this touch and set the gesture state - (void)triggerWithState:(UIGestureRecognizerState)state touches:(NSSet *)touches { if (!touches || !touches.count) return; UITouch *touch = touches.allObjects.firstObject; // normalize the force to a usable value (0.0 - 1.0) _force = touch.force / MIN(touch.maximumPossibleForce, 4.0f); // set the state as Recognized when the force is greater than the triggerForce and conditions are appropriate if (((_triggerOncePerTouch && !_recognized) || (!_triggerOncePerTouch && !_recognized)) && _force >= _triggerForce) { [self _generateFeedback]; self.state = UIGestureRecognizerStateRecognized; } else { _recognized = NO; self.state = state; } } #pragma mark Internal // apply default settings - (void)_applyDefaults { [self setCancelsTouchesInView:NO]; _triggerForce = 0.5f; _triggerOncePerTouch = YES; } // play feedback - (void)_generateFeedback { if (@available(iOS 10.0, *)) { UIImpactFeedbackGenerator *generator = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight]; [generator prepare]; [generator impactOccurred]; generator = nil; } else { AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); } } @end