UIWebView中的滑动手势识别

6

我看过很多这方面的问题,但似乎没有一个能够达到我想要的效果...假设我有一个任意的UIWebView在一个UIViewController中。该UIViewController有一个SwipeGestureRecognizer可以正常工作。它甚至可以在UIWebView内部工作——只要没有滚动条。(在我加载页面之前,或者如果我加载一个适合我的UIWebView大小的页面时)。然而,如果我加载需要水平左右滚动的网页,则在我的视图的UIWebView部分内,我无法识别任何滑动手势。每次点击/拖动/滑动都会触发滚动操作。是否有一种方法来区分“轻扫”和仅用手指滚动(不是抬起手指而是拖动以滚动)。

3个回答

24

是的,你可以告诉UIWebView的UIScrollView仅在你自己的UISwipeGestureRecognizer失败时才触发其UIPanGestureRecognizer。

方法如下:

UISwipeGestureRecognizer *rightSwipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipeGesture:)];
UISwipeGestureRecognizer *leftSwipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipeGesture:)];
rightSwipeGesture.direction = UISwipeGestureRecognizerDirectionRight;
leftSwipeGesture.direction = UISwipeGestureRecognizerDirectionLeft;
[self.view addGestureRecognizer:rightSwipeGesture];
[self.view addGestureRecognizer:leftSwipeGesture];

[_webView.scrollView.panGestureRecognizer requireGestureRecognizerToFail:rightSwipeGesture];
[_webView.scrollView.panGestureRecognizer requireGestureRecognizerToFail:leftSwipeGesture];

那应该可以解决你的问题。


1
天才,省了我很多时间! - Milan Mendpara
1
我还没有测试过,但我认为它会覆盖UIWebview的默认滚动。这不是对的吗? - Syed Danish Ali
很遗憾,这个并没有按照预期的方式工作。一切似乎和之前一样。在水平滚动时,如果网页视图有一些需要滚动的水平列表,则滑动手势将无法在那里被接受。 - Syed Danish Ali
@SyedDanishAli,你是在说要使用JavaScript在web视图内部识别滑动手势并在同一web视图上本地化使用UISwipeGestureRecognizer吗?如果这样做不起作用,我不会感到惊讶:其中一个滑动手势识别器必须“胜出”。 - Johannes Fahrenkrug

2

2
你能描述一下如何进行吗?文档中说:“不应该对UIWebView类进行子类化”。http://developer.apple.com/library/ios/#documentation/uikit/reference/UIWebView_Class/Reference/Reference.html - MrHappyAsthma

1

Johannes Fahrenkrug的回答成功地有条件地阻止了webView的内置pan手势。然而,我发现这只在webView的pan手势非常缓慢时才有效...如果我用任何合理的速度滑动webView,就会触发滑动手势。我只想快速滑动触发滑动手势,中等或缓慢的滑动使用默认的webView滚动功能。

UISwipeGestureRecognizer没有自定义滑动速度的属性,UIPanGestureRecognizer有一个速度属性,但没有设置所需速度的方法,因此我根据这个教程设置了一个自定义手势识别器:

FastSwipeGestureRecognizer.h

#import <UIKit/UIKit.h>
#import <UIKit/UIGestureRecognizerSubclass.h>

#define REQUIRED_TOUCHES 5
#define REQUIRED_STRAIGHTNESS 3
#define REQUIRED_TIME .1

typedef enum {
    DirectionUp = 0,
    DirectionRight,
    DirectionDown,
    DirectionLeft
} Direction;

@interface FastSwipeGestureRecognizer : UIGestureRecognizer {
    CGPoint firstTouchLocation;
    NSTimeInterval firstTouchTime;
    int touchesCount;

    Direction direction;
}

@property (nonatomic) CGPoint firstTouchLocation;
@property (nonatomic) NSTimeInterval firstTouchTime;
@property (nonatomic) int touchesCount;

@property (nonatomic) Direction direction;

@end

FastSwipeGestureRecognizer.m

#import "FastSwipeGestureRecognizer.h"

@implementation FastSwipeGestureRecognizer

@synthesize firstTouchLocation;
@synthesize firstTouchTime;
@synthesize touchesCount;

-(void)reset {
    [super reset];
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesBegan:touches withEvent:event];
    self.firstTouchLocation = [[touches anyObject] locationInView:self.view];
    self.firstTouchTime = [NSDate timeIntervalSinceReferenceDate];
    self.touchesCount = 1;
    self.state = UIGestureRecognizerStatePossible;
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesMoved:touches withEvent:event];
    self.touchesCount++;
    if (self.touchesCount > REQUIRED_TOUCHES) { // wait until we have a few touches before we evaluate the gesture
        CGPoint thisTouchLocation = [[touches anyObject] locationInView:self.view];
        float horizontalRatio = (ABS(thisTouchLocation.x - self.firstTouchLocation.x) / ABS(thisTouchLocation.y - self.firstTouchLocation.y));
        float verticalRatio = 1 / horizontalRatio;
        NSTimeInterval elapsedTime = [NSDate timeIntervalSinceReferenceDate] - self.firstTouchTime;
        NSLog(@"swipe? %f, %f, %f", verticalRatio, horizontalRatio, elapsedTime);

        // if we're moving straight enough and fast enough, complete the gesture
        if (((horizontalRatio > REQUIRED_STRAIGHTNESS)||(verticalRatio > REQUIRED_STRAIGHTNESS))&&(elapsedTime < REQUIRED_TIME)) {
            if (horizontalRatio > REQUIRED_STRAIGHTNESS) {
                self.direction = (thisTouchLocation.x > self.firstTouchLocation.x) ? DirectionRight : DirectionLeft ;
            } else if (verticalRatio > REQUIRED_STRAIGHTNESS) {
                self.direction = (thisTouchLocation.y > self.firstTouchLocation.y) ? DirectionDown : DirectionUp ;
            }
            self.state = UIGestureRecognizerStateRecognized;
        } else {
            self.state = UIGestureRecognizerStateFailed;
        }
    }
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesEnded:touches withEvent:event];
    if (self.touchesCount < REQUIRED_TOUCHES) {
        self.state = UIGestureRecognizerStateFailed;
    }
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesCancelled:touches withEvent:event];
    self.state = UIGestureRecognizerStateFailed;
}

@end

设置手势。
FastSwipeGestureRecognizer *swipeGesture = [[FastSwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipeGesture:)];
[self.view addGestureRecognizer:swipeGesture];
[self.webView.scrollView.panGestureRecognizer requireGestureRecognizerToFail:swipeGesture];

然后检测接收到的手势方向。
- (void)handleSwipeGesture:(FastSwipeGestureRecognizer *)gesture {
    if (gesture.state == UIGestureRecognizerStateEnded) {
        if (gesture.direction == DirectionRight) {
            // do something
        } else if (gesture.direction == DirectionLeft) {
            // do something
        } else if (gesture.direction == DirectionUp) {
            // do something
        } else if (gesture.direction == DirectionDown) {
            // do something
        }
    }
}

请注意,这只需要一个手势来处理所有四个滑动方向,而不是每个方向一个UISwipeGestureRecognizer。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接