41

我试图让 UIGestureRecognizer 与 UIWebview 一起工作,它是 UIScrollView 的子视图。这听起来很奇怪,但是当我numberOfTouchesRequired设置为 2 时,选择器会触发,但是当numberOfTouchesRequired设置为 1 时,选择器不会触发。

这是我的代码:

UITapGestureRecognizer *tap1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(select1:)];
    tap1.numberOfTouchesRequired = 2;
    tap1.numberOfTapsRequired = 1;
    tap1.delegate = self;
    [self.ans1WebView addGestureRecognizer:tap1];
    [tap1 release];

- (void) select1:(UILongPressGestureRecognizer *)sender {
    //Do Stuff
}

我已经通过使用 UIGestureRecognizer 的 Apple 示例并在其 nib 中插入 webview 来确认这一点。他们的点击代码可以在任何地方工作,但在 web 视图的区域内。

4

7 回答 7

68

据我所见,UIWebView 与其他人玩得并不好。对于手势识别器,您可以尝试从以下位置返回 YES:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;

我必须向后兼容 3.0,所以我最终在 UIWebView 中使用 Javascript 进行所有手势处理。不是一个好的解决方案,但它满足我的需求。我能够捕捉一个元素上的长按,以及点击、滑动、捏合和旋转。当然,我只使用本地内容。

编辑:

您可以在PhoneGap中查看向 UIWebView 的委托发送消息的示例。简而言之,您使用document.location = "myscheme:mycommand?myarguments"then 解析此委托回调中的命令和参数:

-(BOOL) webView:(UIWebView *)inWeb shouldStartLoadWithRequest:(NSURLRequest *)inRequest navigationType:(UIWebViewNavigationType)inType {
  if ( [[[inRequest URL] absoluteString] hasPrefix:@"myscheme:"] ) {
    //.. parse arguments
    return NO;
  }
}

您可以在 PhoneGap 代码中看到他们设置了一个队列和计时器来发送消息。根据您的使用情况,您可能需要执行相同的操作。关于这个主题还有其他关于 SO 的问题。

这是事件处理文档。就我而言,我将事件侦听器添加到documentfrom<body onload="myloader();">

function myloader() {
    document.addEventListener( 'touchcancel' , touch_cancel , false );
    document.addEventListener( 'touchstart' , touch_start , false );
    document.addEventListener( 'touchmove' , touch_move , false );
    document.addEventListener( 'touchend' , touch_end , false );
};

实际的事件处理很大程度上取决于您的需求。每个事件处理程序都将接收一个带有 touches 属性的TouchEvent,其中每个项目都是一个Touch。您可以在 touchstart 处理程序中记录开始时间和位置。如果触摸移动到很远或经过错误的时间,则不是长触摸。

WebKit 可能会尝试处理长触摸来开始选择和复制。在您的事件处理程序中,您可以使用它event.preventDefault();来停止默认行为。我还发现-webkit-user-select:nonecss 属性在某些事情上很方便。

var touch = {};
function touch_start( event /*TouchEvent*/ {
  event.preventDefault();
  touch = {};
  touch.startX = event.touches.item(0).pageX;
  touch.startY = event.touches.item(0).pageY;
  touch.startT = ( new Date() ).getTime();
}

这只是我使用 javascript 的第二个项目。你可以在别处找到更好的例子。

如您所见,这不能快速解决您的问题。我对我得到的结果很满意。我正在使用的 html 除了一两个链接之外没有任何交互元素。

于 2010-05-26T03:15:58.070 回答
45

UIWebView 有自己的私有视图,它还附加了手势识别器。因此,优先规则使添加到 UIWebView 的任何手势识别器无法正常工作。

一种选择是实现 UIGestureRecognizerDelegate 协议并实现方法gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer。从此方法返回 YES 用于其他点击手势。这样,您将调用您的点击处理程序,并且 Web 视图仍将被调用。

在 Apple 开发者论坛上查看。

于 2010-10-22T01:29:54.730 回答
13

这是一个有点骇人听闻的解决方案,但它确实有效。UIWebView 有很多内部手势识别器,如果不使用私有 API,您通常无法访问它们。但是,当您实施gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:. 此时,您可以告诉所有内部 UITapGestureRecognizer 仅在您自己的 UITapGestureRecognizer 失败时触发。您只需执行一次,然后从您自己的手势识别器中删除委托。结果是您仍然可以平移和滚动您的 webView,但它不会再接收任何(单个)点击手势。

- (void)viewDidLoad 
{      
    [super viewDidLoad];

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];

    // view is your UIViewController's view that contains your UIWebView as a subview
    [self.view addGestureRecognizer:tap];

    tap.delegate = self;
}

- (void)handleTapGesture:(UITapGestureRecognizer *)gestureRecognizer
{
    NSLog(@"tap!");

    // this is called after gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: so we can safely remove the delegate here
    if (gestureRecognizer.delegate) {
        NSLog(@"Removing delegate...");
        gestureRecognizer.delegate = nil;
    }
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    if ([otherGestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
        [otherGestureRecognizer requireGestureRecognizerToFail:gestureRecognizer];

        NSLog(@"added failure requirement to: %@", otherGestureRecognizer);
    }

    return YES;
}

享受!

于 2013-09-16T18:36:15.890 回答
4

我遇到了同样的问题。这个解决方案对我有用:

1)确保将协议添加到您的界面: UIGestureRecognizerDelegate 例如:

@interface ViewController : UIViewController <SlideViewProtocol, UIGestureRecognizerDelegate>

2)添加这行代码

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES
}

3) 设置手势

UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(nextSlide)];
swipeGesture.numberOfTouchesRequired = 1;
swipeGesture.direction = (UISwipeGestureRecognizerDirectionLeft);
swipeGesture.cancelsTouchesInView = YES; [swipeGesture setDelegate:self];
[self.view addGestureRecognizer:swipeGesture];
于 2013-05-28T05:49:51.057 回答
3
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer {
    return YES;
}
于 2013-10-26T10:51:51.650 回答
2

另一种方法是在 UIWebView 上放置一个透明的 UIButton 并处理来自该按钮的点击。在某些情况下,这可能是一个很好的解决方案。

UIWebView webView = [UIWebView new];
//...

UIButton *transparentButton = [UIButton buttonWithType:UIButtonTypeCustom];
[transparentButton addTarget:self action:@selector(buttonTapped) forControlEvents:(UIControlEventTouchUpInside)];
transparentButton.frame = webView.frame;
transparentButton.layer.backgroundColor = [[UIColor clearColor] CGColor];
[self.view transparentButton];
于 2013-09-06T17:20:42.263 回答
1

您可能还会发现我的回答在这里很有帮助。这是在 UIWebView 的 javascript 中处理捏合手势的工作示例。

(如果您愿意,可以将事件传回给 Objective-C。请参阅我的答案。)

于 2010-09-02T21:37:18.510 回答