【问题标题】:Handling touches inside UIWebview处理 UIWebview 内部的触摸
【发布时间】:2010-11-02 17:10:45
【问题描述】:

我创建了 UIWebView 的子类,并实现了 touchesBegantouchesMovedtouchesEnded 方法。

但是 webview 子类没有处理 touch 事件。

UIWebView子类里面有没有办法处理触摸事件???

【问题讨论】:

  • 我不明白你为什么要覆盖 UIWebView 处理的触摸事件。您的用户将想要放大和缩小网站,以及触摸以单击 hpyerlinks 等。您在上面发布的代码在触摸方法中没有任何实现......我认为了解什么很重要你正在努力完成。在 Web 视图中覆盖触摸事件对我来说似乎是个坏主意。是否有其他方法可以完成您在应用中寻找的行为?
  • 我不希望开发人员提供这样的 cmets。 “在 Web 视图中覆盖触摸事件对我来说似乎是个坏主意”注意“Stanza”和“Kindle”它们如何子类化/挂钩 UIWebView 以处理事件。
  • 只是在寻找更多信息,伙计,放松。
  • 我会怀疑子类化 UIWebView 时的任何行为。开发文档说它不能被子类化。我假设编译器、事件处理、runloop 等将允许子类,但我不相信可能的副作用。此外,您的代码可能会在未来的版本中停止协同工作。你能解释一下你想用子类 UIWebView 做什么吗?
  • 替换自定义 UIWindow 的方法不适用于新的故事板方法。也许 Apple 应该有一些方法,至少可以返回 UIWebView/WebView 内的触摸位置。有多难(著名的遗言,我知道)?

标签: iphone uiwebview


【解决方案1】:

不需要子类化,只需添加UITapGestureRecognizer

UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTapMethod)];
[tap setNumberOfTapsRequired:1]; // Set your own number here
[tap setDelegate:self]; // Add the <UIGestureRecognizerDelegate> protocol

[self.myWebView addGestureRecognizer:tap];

在头文件中添加&lt;UIGestureRecognizerDelegate&gt;协议,并添加此方法:

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

【讨论】:

  • 我需要在 Web 视图顶部单击一下来显示和隐藏导航控制器的导航栏,这种方法对我来说非常有效。
  • 我做了所有这些,但是在一种情况下,直到我还实现了UIGestureRecognizerDelegate- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch 并返回了YES,这才起作用。
【解决方案2】:

如果您只需要处理手势,同时保留 UIWebView 的其余功能不变,您可以继承 UIWebView 并使用此策略:

在你的 UIWebView 子类的 init 方法中,添加一个手势识别器,例如:

UISwipeGestureRecognizer  * swipeRight = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(handleSwipeGestureRightMethod)];
swipeRight.direction = UISwipeGestureRecognizerDirectionRight;
[self addGestureRecognizer:swipeRight];
swipeRight.delegate = self;

然后,将此方法添加到您的类中:

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

将您指定的选择器添加并处理到类中,在本例中为“handleSwipeGestureRightMethod”,然后您就可以开始了...

【讨论】:

  • 使用手势识别器似乎是最干净的方式。
【解决方案3】:

您可以在您的UIWebView 上放置一个UIView,并覆盖touchesDidBegin 等,然后将它们发送到您的网络视图。例如:

用户触摸你的UIView,这会引发

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{  
    // Execute your code then send a touchesBegan to your webview like so:
[webView touchesBegan:touches withEvent:event];
return;
}

您的UIView 必须位于网络视图上方。

【讨论】:

  • 这是一个 iphone 应用程序,它使用 UIKit 框架,我猜 NSView 仅用于开发 Mac 应用程序,并且在 AppKit 框架中可用。
【解决方案4】:

我不确定这是否是您想要的(这不是您所要求的,但它可能会根据您的最终游戏是什么起作用),但您可以改为从 UIWebView 内部解释 JavaScript 中的触摸,并且让javascript去做

document.location='http://null/'+xCoord+'/'+yCoord; // Null is arbitrary.

然后你可以使用 UIWebView 的委托方法来捕捉它

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType

如果 request.URL.host(或其他任何内容)为 isEqualToString:@"null" 则采取相关操作(并返回 NO 而不是 YES)。您甚至可以通过执行以下操作将 JS 添加到每个页面:

- (void)webViewDidFinishLoad:(UIWebView *)webView {
  [webView stringByEvaluatingJavaScriptFromString:@"window.ontouchstart=function(/* ... */);"];
}

希望这有帮助吗?

【讨论】:

  • 是的,虽然不是window.onmousedown!也许开始接触了。
  • 这种方法不能正常工作。它似乎只适用于可点击的 html 项目作为图像和链接。点击div、p、body、document标签时似乎没有效果:(
【解决方案5】:

在 UIWebView 上处理手势在 this Apple Developer forum thread 中讨论。

使用那里提供的信息,在大多数或所有情况下都不需要额外的视图,并且如前所述,覆盖 UIWebView 不是要走的路。

复制粘贴线程中最重要的帖子:

这是一个已知问题。 UIWebView 有自己的 UITapGestureRecognizers,它们位于 UIWebView 本身的私有子视图上。 UIGestureRecognizer 优先级定义附加到视图层次结构更深的视图的手势将排除超级视图上的手势,因此 Web 视图的点击手势将始终胜过您的。

如果在您的情况下允许您的点击与 Web 视图的正常点击一起发生是可以的,那么您最好的解决方案是实现 UIGestureRecognizerDelegate 方法gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer 并为其他点击手势返回 YES。这样,您将调用您的点击处理程序,而 Web 视图仍将被调用。

如果您需要成为唯一处理点击的人,则必须将 UITapGestureRecognizer 子类化,以便可以使用 UIGestureRecognizerSubclass.h 中的单向覆盖,然后您可以从 canBePreventedByGestureRecognizer 返回 NO:当被问及 Web 视图是否点击手势识别器可以阻止你的。

无论如何,我们都知道这一点,并希望在未来能变得更容易。

【讨论】:

    【解决方案6】:

    我刚刚发现 UIWebView 确实会检查它是否响应 - (void)webViewDidNotClick: (id)webBrowserView 选择器,一旦点击视图区域(而不是在 hyperref 或任何其他应专门处理的区域)。所以你可以用你的处理代码来实现那个选择器:)

    【讨论】:

    • 由于某种原因,我无法使用此方法检测到双击。
    • 这应该去哪里?我将它添加到我的 UIWebView 委托中,但没有奏效。
    • 不是委托,你应该继承 UIWebView 本身并重写这个选择器,例如 ` -(void) webViewDidNotClick:(id)webBrowserView { [self.superview touchesEnded:nil withEvent:nil]; } `
    • 我猜这已经被删除了
    【解决方案7】:

    你的意思是当 touchesBegan、touchesMoved 和 touchesEnded 被调用时,你的子类实现没有被调用?

    这听起来像是您如何创建对象实例的问题。我认为需要更多细节。

    (取自 cmets)

    头文件

    #import <UIKit/UIKit.h> 
    
    @interface MyWebView : UIWebView { } @end 
    

    实施文件

    #import "MyWebView.h" 
    
    @implementation MyWebView 
    
    - (id)initWithFrame:(CGRect)frame { 
        if (self = [super initWithFrame:frame]) { } return self; 
    } 
    
    - (void)drawRect:(CGRect)rect { 
        NSLog(@"MyWebView is loaded"); 
    } 
    
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 
       NSLog(@"touches began"); 
    } 
    
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 
        NSLog(@"Touches ended");     
    } 
    
    - (void)dealloc { 
       [super dealloc]; 
    } 
    
    @end
    

    【讨论】:

    • #import @interface MyWebView : UIWebView { } @end #import "MyWebView.h" @implementation MyWebView - (id)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { } return self; } - (void)drawRect:(CGRect)rect { NSLog(@"MyWebView 已加载"); } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@"touches started"); } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@"Touches end"); } - (void)dealloc { [super dealloc]; } @end
    • 你在哪里调用 MyWebView *obj = [[MyWebView alloc] initWithFrame:CGMakeZero];
    【解决方案8】:

    我会尝试在 UIWindow 上覆盖 -sendEvent:,看看是否可以拦截这些触摸事件。

    【讨论】:

      【解决方案9】:

      按照 Unfalkster 所说的,您可以使用 hitTest 方法来实现您想要的,但您不必继承 UIWindow。只需将其放在您的 Web 视图子类中即可。您将收到编译时警告,但它确实有效:

      - (void)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
          if (event.type == UIEventTypeTouches) {
      
              // get location info
              CGFloat x = point.x;
              CGFloat y = point.y;
      
              // get touches
              NSSet *touches = [event allTouches];
      
              // individual touches
              for (UITouch *touch in touches) {
      
                  if (touch.phase == UITouchPhaseBegan) {
                      // touches began
      
                  } else if (touch.phase == UITouchPhaseMoved) {
      
                  }
      
                  // etc etc
              }
          }
      
          // call the super
          [super hitTest:point withEvent:event];
      }
      

      希望有帮助!

      【讨论】:

      • 这很奇怪......出于某种原因 [event allTouches] 总是返回一个空集
      • 通常hitTest:withEvent: 方法返回UIView*。这是故意遗漏的吗?
      • 如果你不从这个方法返回 UIView 会崩溃
      【解决方案10】:

      如果您想检测自己的点击但禁用 UIWebView 的点击,那么您可以使用我的解决方案:

      -(void)recursivelyDisableTapsOnView:(UIView*)v{
          for(UIView* view in v.subviews){
              for(UIGestureRecognizer* g in view.gestureRecognizers){
                  if(g == self.ownTapRecognizer){
                      continue;
                  }
                  if([g isKindOfClass:[UITapGestureRecognizer class]] ||
                     [g isKindOfClass:[UILongPressGestureRecognizer class]] ||
                     [g isKindOfClass:NSClassFromString(@"UITapAndAHalfRecognizer")]){
                      g.enabled = NO;
                  }
              }
              [self recursivelyDisableTapsOnView:view];
          }
      }
      
      
      - (void)webViewDidFinishLoad:(UIWebView *)webView{
          [self recursivelyDisableTapsOnView:webView];
      
          //disable selection
          [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitUserSelect='none';"];
          // Disable callout
          [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitTouchCallout='none';"];
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-18
        相关资源
        最近更新 更多