1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import "ios/chrome/browser/ui/side_swipe_gesture_recognizer.h"
9 #include "base/logging.h"
13 // The absolute maximum swipe angle from |x = y| for a swipe to begin.
14 const CGFloat kMaxSwipeYAngle = 65;
15 // The distance between touches for a swipe to begin.
16 const CGFloat kMinSwipeXThreshold = 4;
20 @implementation SideSwipeGestureRecognizer {
21 // Expected direction of the swipe, based on starting point.
22 UISwipeGestureRecognizerDirection _direction;
25 @synthesize swipeEdge = _swipeEdge;
26 @synthesize direction = _direction;
27 @synthesize swipeOffset = _swipeOffset;
28 @synthesize startPoint = _startPoint;
30 // To quickly avoid interference with other gesture recognizers, fail
31 // immediately if the touches aren't at the edge of the touched view.
32 - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
33 [super touchesBegan:touches withEvent:event];
35 // Don't interrupt gestures in progress.
36 if (self.state != UIGestureRecognizerStatePossible)
39 UITouch* touch = [[event allTouches] anyObject];
40 CGPoint location = [touch locationInView:self.view];
42 if (location.x > _swipeEdge &&
43 location.x < CGRectGetMaxX([self.view bounds]) - _swipeEdge) {
44 self.state = UIGestureRecognizerStateFailed;
46 if (location.x < _swipeEdge) {
47 _direction = UISwipeGestureRecognizerDirectionRight;
49 _direction = UISwipeGestureRecognizerDirectionLeft;
51 _startPoint = location;
54 _startPoint = location;
59 - (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
60 // Revert to normal pan gesture recognizer characteristics after state began.
61 if (self.state != UIGestureRecognizerStatePossible) {
62 [super touchesMoved:touches withEvent:event];
67 if ([[event allTouches] count] > 1) {
68 self.state = UIGestureRecognizerStateFailed;
72 // Don't swipe at an angle greater than |kMaxSwipeYAngle|.
73 UITouch* touch = [[event allTouches] anyObject];
74 CGPoint currentPoint = [touch locationInView:self.view];
75 CGFloat dy = currentPoint.y - _startPoint.y;
76 CGFloat dx = std::abs(currentPoint.x - _startPoint.x);
77 CGFloat degrees = std::fabs(std::atan2(dy, dx) * 180 / CGFloat(M_PI));
78 if (degrees > kMaxSwipeYAngle) {
79 self.state = UIGestureRecognizerStateFailed;
83 // Don't recognize swipe in the wrong direction.
84 if ((_direction == UISwipeGestureRecognizerDirectionRight &&
85 currentPoint.x - _startPoint.x < 0) ||
86 (_direction == UISwipeGestureRecognizerDirectionLeft &&
87 currentPoint.x - _startPoint.x > 0)) {
88 self.state = UIGestureRecognizerStateFailed;
92 if (_swipeEdge == 0 && _direction == 0) {
93 if (currentPoint.x > _startPoint.x) {
94 _direction = UISwipeGestureRecognizerDirectionRight;
96 _direction = UISwipeGestureRecognizerDirectionLeft;
100 // Begin recognizer after |kMinSwipeXThreshold| distance swiped.
101 if (std::abs(currentPoint.x - _startPoint.x) > kMinSwipeXThreshold) {
102 if (_direction == UISwipeGestureRecognizerDirectionRight) {
103 _swipeOffset = currentPoint.x;
105 _swipeOffset = -(CGRectGetMaxX([self.view bounds]) - currentPoint.x);
108 self.state = UIGestureRecognizerStateBegan;
113 - (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
114 _startPoint = CGPointZero;
115 [super touchesEnded:touches withEvent:event];
118 - (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event {
119 _startPoint = CGPointZero;
120 [super touchesCancelled:touches withEvent:event];