UIWebView作为一个UIViewController的子视图,会遮挡住这个viewcotroller.view的touch事件,不能向下传递。在网上搜索了下,常用解决方法:创建UIView子类,重写touchesBegan等方法,添加这个类的实例放在webview上面,并设置为透明。
下面介绍另一个方法:创建UIWindow的子类 TouchCapturingWindow,重写sendEvent方法,自定义哪个View来决定接收Touch。
TouchCapturingWindow.h
#import <UIKit/UIKit.h>
@interface TouchCapturingWindow : UIWindow {
NSMutableArray *views;
@private
UIView *touchView;
}
- (void)addViewForTouchPriority:(UIView*)view;
- (void)removeViewForTouchPriority:(UIView*)view;
@end
TouchCapturingWindow.m
#import "TouchCapturingWindow.h"
@implementation TouchCapturingWindow
- (void)addViewForTouchPriority:(UIView*)view {
if ( !views ) views = [[NSMutableArray alloc] init];
[views addObject:view];
}
- (void)removeViewForTouchPriority:(UIView*)view {
if ( !views ) return;
[views removeObject:view];
}
- (void)sendEvent:(UIEvent *)event {
//get a touch
UITouch *touch = [[event allTouches] anyObject];
//check which phase the touch is at, and process it
if (touch.phase == UITouchPhaseBegan) {
for ( UIView *view in views ) {
//NOTE: I added the isHidden check so that hiding the windows doesn't catch events
//and changed it checks if the touch is in the frame.
//if ( CGRectContainsPoint([view frame], [touch locationInView:[view superview]]) ) {
if ( ![view isHidden] && [view pointInside:[touch locationInView:view] withEvent:event] ) {
touchView = view;
[touchView touchesBegan:[event allTouches] withEvent:event];
break; //NOTE: this used to be a return in the previous version
}
}
}
else if (touch.phase == UITouchPhaseMoved) {
if ( touchView ) {
[touchView touchesMoved:[event allTouches] withEvent:event];
}
}
else if (touch.phase == UITouchPhaseCancelled) {
if ( touchView ) {
[touchView touchesCancelled:[event allTouches] withEvent:event];
touchView = nil;
}
}
else if (touch.phase == UITouchPhaseEnded) {
if ( touchView ) {
[touchView touchesEnded:[event allTouches] withEvent:event];
touchView = nil;
}
}
//we need to send the message to the super for the
//text overlay to work (holding touch to show copy/paste)
[super sendEvent:event];
}
使用:在AppDelegate初始化UIWindow时,将TouchCapturingWindow的实例对象赋值给window
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[TouchCapturingWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// ...
}
在viewController中使用
- (void)viewDidLoad {
[super viewDidLoad];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.youkuaiyun.com"]];
[self.webView loadRequest:request];
mWindow = (TouchCapturingWindow *)[[UIApplication sharedApplication].windows objectAtIndex:0];
[mWindow addViewForTouchPriority:self.webView];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(@" == touchesBegan ==");
}
大功告成,点击webview或其他subview,都可以在viewcontroller中接收到touch处理事件。 注:一般的UIView类和其子类直接设置setUserInteractionEnabled为NO即可。
------------------ 2013.7.17 更新 -----------------------
用js可以更方便获得来自UIWebView的touch事件,实例代码
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.webview.delegate=self;
NSString *resourcePath = [ [NSBundle mainBundle] resourcePath];
NSString *filePath = [resourcePath stringByAppendingPathComponent:@"test.html"];
NSString *htmlstring=[[NSString alloc] initWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
NSString *newHTMLString=[htmlstring stringByAppendingString:@"<script language=\"javascript\">document.ontouchstart=function(){document.location=\"myweb:touch:start\";}; document.ontouchend=function(){document.location=\"myweb:touch:end\";}; document.ontouchmove=function(){document.location=\"myweb:touch:move\";}</script>"];
[self.webview loadHTMLString:newHTMLString baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]];
}
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
NSString *requestString = [[request URL] absoluteString];
NSArray *components = [requestString componentsSeparatedByString:@":"];
if ([components count] > 1 && [(NSString *)[components objectAtIndex:0] isEqualToString:@"myweb"]) {
if([(NSString *)[components objectAtIndex:1] isEqualToString:@"touch"])
{
NSLog(@"%@",[components objectAtIndex:2]);
}
return NO;
}
return YES;
}