2009-09-08 48 views
7

我有一个UIWebView与我想要自动隐藏的导航栏和工具栏。我已经这样做了,但我想在用户点击UIWebView时显示它们。检测UIWebView内的水龙头

我的问题是,UIWebView捕获所有触摸事件,我不能截取我需要的。

有没有解决方法?

回答

1

大多数方法处理复杂的一对UIViewUIWebView子类和overrode -touchesBegan:withEvent:等方法。

This JavaScript-based approach拦截触及到网络DOM本身,它似乎是避开更复杂过程的聪明方法。我自己并没有尝试过,但我很想知道结果,如果你给它一个镜头。

+0

看起来像一个聪明的解决方法。我会给它一个镜头并发布我的结果。 – pgb 2009-09-09 01:22:08

+1

刚刚尝试过。问题是,当你随机点击屏幕时,iPhone不会发布Javascript onclick事件。它似乎只在有关联的对象时发送它们。 – pgb 2009-09-09 19:02:59

+0

您可以轻松使用UITapGestureRecognizer,查看我的答案。 – 2014-03-20 16:40:40

1

我不确定确切的实现细节,但您需要继承UIWindow并覆盖sendEvent :.然后,您可以捕捉轻敲事件并相应地处理它们,然后才能进入Web视图。希望这能指出你正确的方向!

8

采取自blog entry(不加载,但幸好它是Google Cache'dMithin Kumar

(Mithin,我希望你不介意我在这里重新张贴;如果你这样做,请让我知道在评论中,我将其删除。)

最近,我工作的一个该项目需要检测UIWebView上的点击和事件。我们想找出用户在UIWebView中点击的HTML元素,然后根据点击的元素执行一些操作。在谷歌搜索之后,我发现大多数用户在UIWebView上放置了一个透明的UIView,重新实现了UIResponder类的触摸方法(例如:-touchesBegan:withEvent :),然后将事件传递给UIWebView。该方法详细解释here。该方法存在多个问题。

  1. 复制/选择停止工作的UIWebView
  2. 我们需要而苹果说,我们不应该子类它来创建一个子类的UIWebView的。
  3. 许多其他UIWebView功能停止工作。

我们最终发现实现这个的正确方法是通过 子类化UIWindow并重新实现-sendEvent:方法。这里 是你如何做到的。首先,创建一个一个UIWindow子类

#import <UIKit/UIKit.h> 
@protocol TapDetectingWindowDelegate 
- (void)userDidTapWebView:(id)tapPoint; 
@end 
@interface TapDetectingWindow : UIWindow { 
    UIView *viewToObserve; 
    id <TapDetectingWindowDelegate> controllerThatObserves; 
} 
@property (nonatomic, retain) UIView *viewToObserve; 
@property (nonatomic, assign) id <TapDetectingWindowDelegate> controllerThatObserves; 
@end 

需要注意的是,我们有变量,告诉我们的UIView在其上 检测的事件和接收事件 信息的控制器。现在,实现这个类以下列方式

#import "TapDetectingWindow.h" 
@implementation TapDetectingWindow 
@synthesize viewToObserve; 
@synthesize controllerThatObserves; 
- (id)initWithViewToObserver:(UIView *)view andDelegate:(id)delegate { 
    if(self == [super init]) { 
     self.viewToObserve = view; 
     self.controllerThatObserves = delegate; 
    } 
    return self; 
} 
- (void)dealloc { 
    [viewToObserve release]; 
    [super dealloc]; 
} 
- (void)forwardTap:(id)touch { 
    [controllerThatObserves userDidTapWebView:touch]; 
} 
- (void)sendEvent:(UIEvent *)event { 
    [super sendEvent:event]; 
    if (viewToObserve == nil || controllerThatObserves == nil) 
     return; 
    NSSet *touches = [event allTouches]; 
    if (touches.count != 1) 
     return; 
    UITouch *touch = touches.anyObject; 
    if (touch.phase != UITouchPhaseEnded) 
     return; 
    if ([touch.view isDescendantOfView:viewToObserve] == NO) 
     return; 
    CGPoint tapPoint = [touch locationInView:viewToObserve]; 
    NSLog(@"TapPoint = %f, %f", tapPoint.x, tapPoint.y); 
    NSArray *pointArray = [NSArray arrayWithObjects:[NSString stringWithFormat:@"%f", tapPoint.x], 
    [NSString stringWithFormat:@"%f", tapPoint.y], nil]; 
    if (touch.tapCount == 1) { 
     [self performSelector:@selector(forwardTap :) withObject:pointArray afterDelay:0.5]; 
    } 
    else if (touch.tapCount > 1) { 
     [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(forwardTap :) object:pointArray]; 
    } 
} 
@end 

实现上述方式的SendEvent方法,然后你可以发送回 你要回控制器的信息。

有一些事情需要记住。确保在您的 MainWindow.xib文件中,窗口类型为TapDetectingWindow而不是 UIWindow。只有这样所有事件才会通过以上 重新实现的sendEvent方法。另外,请确保先拨打[super sendEvent:event],然后做任何你想做的事情。现在

,你可以在 控制器类来创建你的UIWebView以下方式

@interface WebViewController : UIViewController<TapDetectingWindowDelegate> { 
    IBOutlet UIWebView *mHtmlViewer; 
    TapDetectingWindow *mWindow; 
} 
- (void)viewDidLoad { 
    [super viewDidLoad]; 
    mWindow = (TapDetectingWindow *)[[UIApplication sharedApplication].windows objectAtIndex:0]; 
    mWindow.viewToObserve = mHtmlViewer; 
    mWindow.controllerThatObserves = self; 
} 

记住,你需要编写方法userDidTapWebView在 控制器类。这是为了将事件信息发送到控制器类而调用的方法。在我们上面的例子中,我们 发送用户点击的UIWebView中的点。

+1

我试过这一堆方法(javascript,透明覆盖视图,内部触摸选择器的方法swishing),但这(mithin.in链接)似乎是最好的,非私人的方式来做到这一点。 – Jason 2010-01-12 22:15:35

+0

这是迄今为止正确的答案! – Jacob 2011-04-06 00:45:44

+0

很好!谢谢 – Joey 2011-11-21 02:30:32

1

创建一个UIView子类包含整个UIWebView。然后事件hitTest将触发webview触发。注意:不要将任何东西放到除webView外的容器中。因为iOS 3.2是简单地使用UITapGestureRecognizer

-(UIView*) hitTest:(CGPoint)point withEvent:(UIEvent *)event 
{ 
    NSLog(@"Hit test %@", [event description]); 
    UIView * returnView = [super hitTest:point withEvent:event]; 
    [delegate userDidTapWebView];// notify the delegate that UIWebView is being touched by some naughty user :P 


    return returnView; 
} 
+0

这种工作取决于你所需要的,但该方法也被称为平移手势(滚动),并且每触摸一次被称为两次。绝对不理想。 – cprcrack 2013-10-23 14:46:32

0

一个更简单的方法:

@interface myWebViewContainer : UIView 
... ... 
@end 

然后重写则hitTest事件。

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view. 
    UITapGestureRecognizer* tapGestureRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:self 
                         action:@selector(userDidTapWebView)] autorelease]; 
    [self.pdfWebView addGestureRecognizer:tapGestureRecognizer]; 

} 

- (void)userDidTapWebView { 
    NSLog(@"TAP"); 
} 
+1

不适用于我。 – Dmitry 2012-08-08 21:01:10

+0

这不适用于Web视图,因为它们包含自己的更高优先级的手势识别器。 – Jeff 2013-10-04 13:26:21

+0

尽管您需要实现UIGestureRecognizerDelegate方法,但此方法仍可行。看到我的答案。 – 2014-03-20 16:39:44

3

我有几个问题想在我的iOS 5-7,使用brian.clear's answer(由Mithin Kumar从灭绝后复制)普遍故事板为主完全ARC的项目,所以我必须做出一些改变。我还改进了一些东西,使其更容易理解(至少对我而言)。如果您在2009年尝试使用该答案时遇到问题,也许您应该尝试更新。详细说明:

1.创建一个新TapDetectingWindow类

TapDetectingWindow.h

// Created by Cristian Perez <[email protected]> 
// Based on https://stackoverflow.com/a/1859883/423171 

#import <UIKit/UIKit.h> 

@protocol TapDetectingWindowDelegate 

- (void)userDidTapView:(CGPoint)tapPoint; 

@end 

@interface TapDetectingWindow : UIWindow 

@property (nonatomic) UIView *tapDetectingView; 
@property (nonatomic) id <TapDetectingWindowDelegate> tapDetectedDelegate; 

@end 

TapDetectingWindow.m

// Created by Cristian Perez <[email protected]> 
// Based on https://stackoverflow.com/a/1859883/423171 

#import "TapDetectingWindow.h" 

@implementation TapDetectingWindow 

@synthesize tapDetectingView; 
@synthesize tapDetectedDelegate; 

- (id)initWithFrame:(CGRect)frame 
{ 
    return [super initWithFrame:frame]; 
} 

- (void)sendEvent:(UIEvent *)event 
{ 
    [super sendEvent:event]; 
    if (tapDetectingView == nil || tapDetectedDelegate == nil) 
    { 
     return; 
    } 
    NSSet *touches = [event allTouches]; 
    if (touches.count != 1) 
    { 
     return; 
    } 
    UITouch *touch = touches.anyObject; 
    if (touch.phase != UITouchPhaseEnded) 
    { 
     return; 
    } 
    if (touch.view != nil && ![touch.view isDescendantOfView:tapDetectingView]) 
    { 
     return; 
    } 
    CGPoint tapPoint = [touch locationInView:tapDetectingView]; 
    NSString *tapPointStr = NSStringFromCGPoint(tapPoint); 
    if (touch.tapCount == 1) 
    { 
     [self performSelector:@selector(notifyTap:) withObject:tapPointStr afterDelay:0.4]; 
     // Make the afterDelay value bigger in order to have more chances of detecting a double tap and thus being able to cancel the single tap event, or make it smaller if you don't care about double taps and want to get the tap event as soon as possible 
    } 
    else if (touch.tapCount > 1) 
    { 
     [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(notifyTap:) object:tapPointStr]; 
    } 
} 

- (void)notifyTap:(NSString *)tapPointStr 
{ 
    CGPoint tapPoint = CGPointFromString(tapPointStr); 
    [tapDetectedDelegate userDidTapView:tapPoint]; 
} 

@end 

2.检查你有window声明在你的应用代理

你应该在YourAppDelegate.h这样的事情。不要更改属性的名称!

@interface YourAppDelegate : UIResponder <UIApplicationDelegate> 
{ 
    // ... 
} 

// ... 

// The app delegate must implement the window property if it wants to use a main storyboard file 
@property (nonatomic) UIWindow *window; 

@end 

3.覆盖的window财产应用程序委托

就这样的,这应该是在YourAppDelegate.m。再次,不要更改方法的名称!

// Replace the default UIWindow property with a TapDetectingWindow 
- (TapDetectingWindow *)window 
{ 
    static TapDetectingWindow *tapDetectingWindow = nil; 
    if (!tapDetectingWindow) 
    { 
     tapDetectingWindow = [[TapDetectingWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 
    } 
    return tapDetectingWindow; 
} 

4.将在您的视图控制器的委托协议

一定要采用自来水处理协议在MainViewController.h

#import "TapDetectingWindow.h" 

@interface MainViewController : UIViewController <TapDetectingWindowDelegate, ...> 
{ 
    // ... 
} 

// ... 

@end 

5.设置自来水检测窗口和点击事件处理程序

指定您的webview(实际上任何UIView都应该工作)并点击v中的事件处理程序IEW控制器的(无效)viewDidLoad中方法

- (void)viewDidLoad 
{ 
    // ... 

    // Allow tap detection in webview 
    TapDetectingWindow *tapDetectingWindow = (TapDetectingWindow*)[(YouTubeRPAppDelegate*)[[UIApplication sharedApplication] delegate] window]; 
    tapDetectingWindow.tapDetectingView = self.webView; // Your UIWebView 
    tapDetectingWindow.tapDetectedDelegate = self; 
} 

6.处理自来水事件,如你所愿

只需实现userDidTapView方法在您的视图控制器

- (void)userDidTapView:(CGPoint)tapPoint 
{ 
    NSLog(@"Tap detected in webview at %@", NSStringFromCGPoint(tapPoint)); 
} 
7

您可以非常简单使用UITapGestureRecognizer检测UIWebView上的轻敲手势。但是,您必须实施UIGestureRecognizerDelegate方法才能允许同时识别。

- (void)viewDidLoad{ 
    [super viewDidLoad]; 

    UITapGestureRecognizer *targetGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; 
    targetGesture.numberOfTapsRequired = 2; 
    targetGesture.delegate = self; 
    [self.webView addGestureRecognizer:targetGesture]; 

} 

// called when the recognition of one of gestureRecognizer or otherGestureRecognizer would be blocked by the other 
// return YES to allow both to recognize simultaneously. the default implementation returns NO (by default no two gestures can be recognized simultaneously) 
// 
// note: returning YES is guaranteed to allow simultaneous recognition. returning NO is not guaranteed to prevent simultaneous recognition, as the other gesture's delegate may return YES 
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{ 
    NSLog(@"%@", otherGestureRecognizer); 
    //if you would like to manipulate the otherGestureRecognizer here is an example of how to cancel and disable it 
    if([otherGestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]){ 

     UITapGestureRecognizer *tapRecognizer = (UITapGestureRecognizer*)otherGestureRecognizer; 
     if(tapRecognizer.numberOfTapsRequired == 2 && tapRecognizer.numberOfTouchesRequired == 1){ 

      //this disalbes and cancels all other singleTouchDoubleTap recognizers 
      // default is YES. disabled gesture recognizers will not receive touches. when changed to NO the gesture recognizer will be cancelled if it's currently recognizing a gesture 
      otherGestureRecognizer.enabled = NO; 

     } 

    } 

    return YES; 

} 

-(void)handleTap:(id)sender{ 



} 
+0

这为我工作,谢谢 – 2014-05-14 22:22:33

+0

我怀疑它不能在iOS的ealier版本中工作,因此,其他答案被接受。有人可以验证它吗? (这个问题太旧了,我认为那时手势识别器可能不可用) – 2015-01-02 13:04:58

相关问题