Index: ios/chrome/browser/ui/side_swipe_gesture_recognizer.mm |
diff --git a/ios/chrome/browser/ui/side_swipe_gesture_recognizer.mm b/ios/chrome/browser/ui/side_swipe_gesture_recognizer.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..66cb5753669a867480ab4028a552454f373b3cf0 |
--- /dev/null |
+++ b/ios/chrome/browser/ui/side_swipe_gesture_recognizer.mm |
@@ -0,0 +1,106 @@ |
+// Copyright 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#import "ios/chrome/browser/ui/side_swipe_gesture_recognizer.h" |
+ |
+#include <cmath> |
+ |
+#include "base/logging.h" |
+ |
+namespace { |
+ |
+// The absolute maximum swipe angle from |x = y| for a swipe to begin. |
+CGFloat kMaxSwipeYAngle = 65; |
+// The distance between touches for a swipe to begin. |
+CGFloat kMinSwipeXThreshold = 4; |
+ |
+} // namespace |
+ |
+@implementation SideSwipeGestureRecognizer { |
+ // Starting point of swipe. |
+ CGPoint _startPoint; |
+ // Expected direction of the swipe, based on starting point. |
+ UISwipeGestureRecognizerDirection _direction; |
+} |
+ |
+@synthesize swipeEdge = _swipeEdge; |
+@synthesize direction = _direction; |
+@synthesize swipeOffset = _swipeOffset; |
+ |
+// To quickly avoid interference with other gesture recognizers, fail |
+// immediately if the touches aren't at the edge of the touched view. |
+- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event { |
+ [super touchesBegan:touches withEvent:event]; |
+ UITouch* touch = [[event allTouches] anyObject]; |
+ CGPoint location = [touch locationInView:self.view]; |
+ if (location.x > _swipeEdge && |
+ location.x < CGRectGetMaxX([self.view bounds]) - _swipeEdge) { |
+ self.state = UIGestureRecognizerStateFailed; |
+ } else { |
+ if (location.x < _swipeEdge) { |
+ _direction = UISwipeGestureRecognizerDirectionRight; |
+ } else { |
+ _direction = UISwipeGestureRecognizerDirectionLeft; |
+ } |
+ _startPoint = location; |
+ } |
+} |
+ |
+- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event { |
+ // Revert to normal pan gesture recognizer characteristics after state began. |
+ if (self.state != UIGestureRecognizerStatePossible) { |
+ [super touchesMoved:touches withEvent:event]; |
+ return; |
+ } |
+ |
+ // Only one touch. |
+ if ([[event allTouches] count] > 1) { |
+ self.state = UIGestureRecognizerStateFailed; |
+ return; |
+ } |
+ |
+ // Don't swipe at an angle greater than |kMaxSwipeYAngle|. |
+ UITouch* touch = [[event allTouches] anyObject]; |
+ CGPoint currentPoint = [touch locationInView:self.view]; |
+ CGFloat dy = currentPoint.y - _startPoint.y; |
+ CGFloat dx = std::abs(currentPoint.x - _startPoint.x); |
+ CGFloat degrees = std::fabs(std::atan2(dy, dx) * 180 / CGFloat(M_PI)); |
+ if (degrees > kMaxSwipeYAngle) { |
+ self.state = UIGestureRecognizerStateFailed; |
+ return; |
+ } |
+ |
+ // Don't recognize swipe in the wrong direction. |
+ if ((_direction == UISwipeGestureRecognizerDirectionRight && |
+ currentPoint.x - _startPoint.x < 0) || |
+ (_direction == UISwipeGestureRecognizerDirectionLeft && |
+ currentPoint.x - _startPoint.x > 0)) { |
+ self.state = UIGestureRecognizerStateFailed; |
+ return; |
+ } |
+ |
+ // Begin recognizer after |kMinSwipeXThreshold| distance swiped. |
+ if (std::abs(currentPoint.x - _startPoint.x) > kMinSwipeXThreshold) { |
+ if (_direction == UISwipeGestureRecognizerDirectionRight) { |
+ _swipeOffset = currentPoint.x; |
+ } else { |
+ _swipeOffset = -(CGRectGetMaxX([self.view bounds]) - currentPoint.x); |
+ } |
+ |
+ self.state = UIGestureRecognizerStateBegan; |
+ return; |
+ } |
+} |
+ |
+- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event { |
+ _startPoint = CGPointZero; |
+ [super touchesEnded:touches withEvent:event]; |
+} |
+ |
+- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event { |
+ _startPoint = CGPointZero; |
+ [super touchesCancelled:touches withEvent:event]; |
+} |
+ |
+@end |