Commit d4efa93d authored by Robbie Gibson's avatar Robbie Gibson Committed by Chromium LUCI CQ

[iOS][Thumb Strip] Prevent simultaneous gesture recognition

Before, it was possible for two gesture recognizers to be simulatneously
recognized. E.g. panning the toolbar while scrolling or panning both the
tab strip and the toolbar. This caused lots of problems.

This CL lets the ViewRevealingVerticalPanHandler track which gesture
recognizer it is currently handling. While it is handling one, all other
gestures are ignored.

Bug: 1161209, 1163518
Change-Id: I3525cfd670a08a5b88166dd5d8c647b7a9b437f0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2618000Reviewed-by: default avatarGauthier Ambard <gambard@chromium.org>
Reviewed-by: default avatarJavier Flores <javierrobles@chromium.org>
Commit-Queue: Robbie Gibson <rkgibson@google.com>
Cr-Commit-Position: refs/heads/master@{#842529}
parent 4085765c
......@@ -57,6 +57,7 @@
UIPanGestureRecognizer* panGestureRecognizer = [[UIPanGestureRecognizer alloc]
initWithTarget:panGestureHandler
action:@selector(handlePanGesture:)];
panGestureRecognizer.delegate = panGestureHandler;
panGestureRecognizer.maximumNumberOfTouches = 1;
[self.view addGestureRecognizer:panGestureRecognizer];
......
......@@ -23,7 +23,9 @@
// to a revealed state (and vice-versa) if the gesture's translation and
// velocity are enough to trigger such transition.
@interface ViewRevealingVerticalPanHandler
: NSObject <CRWWebViewScrollViewProxyObserver, UIScrollViewDelegate>
: NSObject <CRWWebViewScrollViewProxyObserver,
UIGestureRecognizerDelegate,
UIScrollViewDelegate>
// |peekedHeight| is the height of the view when peeked (partially revealed).
// |revealedCoverHeight| is the height of the cover view that remains visible
......
......@@ -65,6 +65,10 @@ const CGFloat kAnimationDuration = 0.25f;
// -scrollViewDidScroll:.
@property(nonatomic, assign) CGPoint lastScrollOffset;
// Holds the gesture recognizer that is currently in progess. Any other
// gestures received while one is active will be ignored.
@property(nonatomic, weak) UIGestureRecognizer* currentRecognizer;
@end
@implementation ViewRevealingVerticalPanHandler
......@@ -103,6 +107,9 @@ const CGFloat kAnimationDuration = 0.25f;
} else if (gesture.state == UIGestureRecognizerStateEnded) {
CGFloat velocityY = [gesture velocityInView:gesture.view.superview].y;
[self panGestureEndedWithTranslation:translationY velocity:velocityY];
self.currentRecognizer = nil;
} else if (gesture.state == UIGestureRecognizerStateCancelled) {
self.currentRecognizer = nil;
}
}
......@@ -431,6 +438,10 @@ const CGFloat kAnimationDuration = 0.25f;
- (void)panHandlerScrollViewWillBeginDragging:
(PanHandlerScrollView*)scrollView {
if (self.currentRecognizer &&
self.currentRecognizer != scrollView.panGestureRecognizer) {
return;
}
switch (self.currentState) {
case ViewRevealState::Hidden: {
// The transition out of hidden state can only start if the scroll view
......@@ -449,14 +460,19 @@ const CGFloat kAnimationDuration = 0.25f;
// be able to be scrolled.
NOTREACHED();
}
self.currentRecognizer = scrollView.panGestureRecognizer;
[self panGestureBegan];
self.lastScrollOffset = scrollView.contentOffset;
}
- (void)panHandlerScrollViewDidScroll:(PanHandlerScrollView*)scrollView {
// These delegate methods are approximating the pan gesture handling from
// above, so only change things if the user is actively scrolling.
if (!scrollView.isDragging) {
// Early return if there is no current recognizer or one that does not match
// this scroll view's recognizer. The first can happen when the scroll view
// scrolls after the user lifts their finger. This should not be handled as
// these methods are only approximating the actual pan gesture handling from
// above. The second can happen if the user scrolls and uses one of the pan
// gestures simultaneously.
if (self.currentRecognizer != scrollView.panGestureRecognizer) {
return;
}
UIPanGestureRecognizer* gesture = scrollView.panGestureRecognizer;
......@@ -481,6 +497,16 @@ const CGFloat kAnimationDuration = 0.25f;
withVelocity:(CGPoint)velocity
targetContentOffset:
(inout CGPoint*)targetContentOffset {
// Early return if there is no current recognizer or one that does not match
// this scroll view's recognizer. The first can happen when the scroll view
// scrolls after the user lifts their finger. This should not be handled as
// these methods are only approximating the actual pan gesture handling from
// above. The second can happen if the user scrolls and uses one of the pan
// gestures simultaneously.
if (self.currentRecognizer != scrollView.panGestureRecognizer) {
return;
}
self.currentRecognizer = nil;
if (self.currentState == ViewRevealState::Hidden &&
self.animator.state != UIViewAnimatingStateActive) {
return;
......@@ -497,4 +523,14 @@ const CGFloat kAnimationDuration = 0.25f;
[self panGestureEndedWithTranslation:translationY velocity:velocityY];
}
#pragma mark - UIGestureRecognizerDelegate
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)gestureRecognizer {
if (self.currentRecognizer) {
return NO;
}
self.currentRecognizer = gestureRecognizer;
return YES;
}
@end
......@@ -568,6 +568,7 @@ UIColor* BackgroundColor() {
UIPanGestureRecognizer* panGestureRecognizer = [[UIPanGestureRecognizer alloc]
initWithTarget:panGestureHandler
action:@selector(handlePanGesture:)];
panGestureRecognizer.delegate = panGestureHandler;
panGestureRecognizer.maximumNumberOfTouches = 1;
[self.view addGestureRecognizer:panGestureRecognizer];
......
......@@ -66,6 +66,7 @@
UIPanGestureRecognizer* panGestureRecognizer = [[UIPanGestureRecognizer alloc]
initWithTarget:panGestureHandler
action:@selector(handlePanGesture:)];
panGestureRecognizer.delegate = panGestureHandler;
panGestureRecognizer.maximumNumberOfTouches = 1;
[self.view addGestureRecognizer:panGestureRecognizer];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment