6

我在 UIWebView 中显示一个文档。我想在文档上放置一个热点以在点击它时触发一个动作,但我也想保持默认的 UIWebView 行为,即在双击文档时自动缩放文档。我不知道如何在让 UIWebView 响应双击时响应单击。

我首先将热点设置为带有动作的透明 UIButton,但双击热点会导致热点动作被调用两次。因此,我从按钮中删除了该操作并附加了一个单击手势:

UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapAction:)];
singleTap.numberOfTapsRequired = 1;
singleTap.delegate = self;
[self.hotspot addGestureRecognizer:singleTap];
[singleTap release];

这与正常的按钮操作相同。但后来我创建了一个双击手势,并将其配置为使用 requireGestureRecognizerToFail 阻止单击手势:

UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(zoomWebView:)];
doubleTap.numberOfTapsRequired = 2;
doubleTap.delegate = self;
[self.hotspot addGestureRecognizer:doubleTap];
[doubleTap release];

UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapAction:)];
singleTap.numberOfTapsRequired = 1;
[singleTap requireGestureRecognizerToFail:doubleTap];
singleTap.delegate = self;
[self.hotspot addGestureRecognizer:singleTap];
[singleTap release];

- (void)zoomWebView:(UITapGestureRecognizer *)gesture {
    NSLog(@"double tap");
}

使用此设置,单击热点调用 singleTapAction,双击热点调用 zoomWebView(自定义方法)。这很好,因为 singleTapAction 不再被调用两次,但很糟糕,因为 UIWebView 不再响应双击。

我尝试通过继承 UITapGestureRecognizer、覆盖 touchesBegan 和 touchesEnded 方法并将它们的参数发送到 UIWebView 的相应方法,将双击事件从我的 doubleTap 手势转发到 UIWebView。当我这样做时,我可以看到我的子类正在接收事件,但 UIWebView 没有响应转发的事件。这是意料之中的,因为iOS 的事件处理指南说我们只能将事件转发到 UIView 的自定义子类,而不是 UIKit 框架对象。

有没有办法阻止我的单击手势响应不会转移双击事件的双击?这似乎是一个基本要求,但我看不到一个直接的方法来做到这一点。我阅读并尝试了 UIGestureRecognizer 的触摸传递属性,但没有任何值组合阻止单击手势消耗双击手势。

顺便说一句,我的视图层次结构中的热点和 UIWebView 之间的关系是“表亲”的关系——它们是两个兄弟视图的子视图。如果我将手势识别器添加到热点视图、Web 视图或它们的“祖父母”视图,我会得到相同的结果。

4

2 回答 2

15

好的,我找到了两个部分的解决方案:

1) 我必须将我的手势添加到 UIWebView 的父视图中。无与伦比的事件不会像我想象的那样在一个层到另一个层的视图中穿过重叠的对象。相反,它们通过从子到父的视图层次结构。因此,只要我将双击手势添加到 UIWebView 的兄弟或“表亲”视图,它就永远不会继续到 Web 视图。这意味着我不能使用 Interface Builder 中布局的按钮或视图来确定多个热点区域。相反,我必须将所有单击事件重定向到一种方法,然后查看触摸位置以确定要触发的操作。

2)我必须将gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:方法添加到我的视图控制器(我的手势代表)并返回YES。即使我在 UIWebView 中显示 HTML、文本或图像内容,这也允许我的单击手势做出响应,它为这些内容类型实现了自己的手势。我从这个答案中学到了这一部分。

通过这些更改,我理解事件的层次结构是:

  • 单击 Web 视图:我在 Web 视图的父视图上的单击手势响应;如果适用,Web 视图的单击手势也会响应,因为同时启用了手势

  • 双击 Web 视图:我在 Web 视图的父视图上的双击手势响应(但不执行任何操作);我的单击手势没有响应,因为它被配置为仅在双击失败时才响应;Web 视图的双击事件也会响应,因为它是视图层次结构的一部分(似乎 Web 视图的双击功能不使用手势,否则在我的原始设置中它会优先于我自己的手势)

有了这个解释,这里有一些工作代码:

- (void)viewDidLoad {
    UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTapWebView:)];
    doubleTap.numberOfTapsRequired = 2;
    doubleTap.delegate = self;
    [self.webViewParent addGestureRecognizer:doubleTap];
    [doubleTap release];

    UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapWebView:)];
    singleTap.numberOfTapsRequired = 1;
    [singleTap requireGestureRecognizerToFail:doubleTap];
    singleTap.delegate = self;
    [self.webViewParent addGestureRecognizer:singleTap];
    [singleTap release];
}

- (void)doubleTapWebView:(UITapGestureRecognizer *)gesture {
    NSLog(@"double-tap");
    // nothing to do here
}

- (void)singleTapWebView:(UITapGestureRecognizer *)gesture {
    NSLog(@"single-tap");
    CGPoint touchLocation = [gesture locationInView:self.webViewParent];
    float x = touchLocation.x;
    float y = touchLocation.y;
    CGRect frame = self.webViewParent.frame;
    if (y < frame.size.height * .33) {
        NSLog(@"top");
    } else if (y > frame.size.height * .67) {
        NSLog(@"bottom");
    } else if (x < frame.size.width * .33) {
        NSLog(@"left");
    } else if (x > frame.size.width * .67) {
        NSLog(@"right");
    } else {
        NSLog(@"center");
    }
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    return YES;
}
于 2012-07-17T18:42:38.450 回答
-2

自事件处理开始以来,鼠标点击一直是个问题。

在单击的情况下,任何软件都不可能确定双击即将发生。

因此,如果要处理单击和双击,则必须自己进行双击处理。

为单击的实例计时,并生成您自己的双击事件。

希望这可以转移到您的上下文中。

于 2012-07-17T00:05:51.600 回答