我有一个UIWebView
与我想要自动隐藏的导航栏和工具栏。我已经这样做了,但我想在用户点击UIWebView
时显示它们。检测UIWebView内的水龙头
我的问题是,UIWebView
捕获所有触摸事件,我不能截取我需要的。
有没有解决方法?
我有一个UIWebView
与我想要自动隐藏的导航栏和工具栏。我已经这样做了,但我想在用户点击UIWebView
时显示它们。检测UIWebView内的水龙头
我的问题是,UIWebView
捕获所有触摸事件,我不能截取我需要的。
有没有解决方法?
大多数方法处理复杂的一对UIView
和UIWebView
子类和overrode -touchesBegan:withEvent:
等方法。
This JavaScript-based approach拦截触及到网络DOM本身,它似乎是避开更复杂过程的聪明方法。我自己并没有尝试过,但我很想知道结果,如果你给它一个镜头。
我不确定确切的实现细节,但您需要继承UIWindow并覆盖sendEvent :.然后,您可以捕捉轻敲事件并相应地处理它们,然后才能进入Web视图。希望这能指出你正确的方向!
采取自blog entry(不加载,但幸好它是Google Cache'd)Mithin Kumar。
(Mithin,我希望你不介意我在这里重新张贴;如果你这样做,请让我知道在评论中,我将其删除。)
最近,我工作的一个该项目需要检测UIWebView上的点击和事件。我们想找出用户在UIWebView中点击的HTML元素,然后根据点击的元素执行一些操作。在谷歌搜索之后,我发现大多数用户在UIWebView上放置了一个透明的UIView,重新实现了UIResponder类的触摸方法(例如:-touchesBegan:withEvent :),然后将事件传递给UIWebView。该方法详细解释here。该方法存在多个问题。
- 复制/选择停止工作的UIWebView
- 我们需要而苹果说,我们不应该子类它来创建一个子类的UIWebView的。
- 许多其他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中的点。
创建一个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;
}
这种工作取决于你所需要的,但该方法也被称为平移手势(滚动),并且每触摸一次被称为两次。绝对不理想。 – cprcrack 2013-10-23 14:46:32
一个更简单的方法:
@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");
}
我有几个问题想在我的iOS 5-7,使用brian.clear's answer(由Mithin Kumar从灭绝后复制)普遍,故事板为主,完全ARC的项目,所以我必须做出一些改变。我还改进了一些东西,使其更容易理解(至少对我而言)。如果您在2009年尝试使用该答案时遇到问题,也许您应该尝试更新。详细说明:
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
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
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;
}
一定要采用自来水处理协议在MainViewController.h
#import "TapDetectingWindow.h"
@interface MainViewController : UIViewController <TapDetectingWindowDelegate, ...>
{
// ...
}
// ...
@end
指定您的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;
}
只需实现userDidTapView方法在您的视图控制器
- (void)userDidTapView:(CGPoint)tapPoint
{
NSLog(@"Tap detected in webview at %@", NSStringFromCGPoint(tapPoint));
}
我尝试了所有上述方法没有成功。 Bhupendra的https://stackoverflow.com/a/11878821/884477的回答对我来说非常合适。
您可以非常简单使用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{
}
这为我工作,谢谢 – 2014-05-14 22:22:33
我怀疑它不能在iOS的ealier版本中工作,因此,其他答案被接受。有人可以验证它吗? (这个问题太旧了,我认为那时手势识别器可能不可用) – 2015-01-02 13:04:58
看起来像一个聪明的解决方法。我会给它一个镜头并发布我的结果。 – pgb 2009-09-09 01:22:08
刚刚尝试过。问题是,当你随机点击屏幕时,iPhone不会发布Javascript onclick事件。它似乎只在有关联的对象时发送它们。 – pgb 2009-09-09 19:02:59
您可以轻松使用UITapGestureRecognizer,查看我的答案。 – 2014-03-20 16:40:40