新答案:
看起来这就是我们想要的,就在这里:
https://dev59.com/SU7Sa4cB1Zd3GeqP7uqB#3198220
旧的回答:
好的,经过一些研究,这是情况:
你在问题中描述的似乎是准确的:
首先,你真的不能向标准上下文菜单的默认菜单项添加其他菜单项。但是你可以使用某个CSS属性关闭上下文菜单。因此,解决方案是关闭默认菜单并从头开始实现自己的菜单。要实现自己的上下文菜单,必须首先捕获选项卡和按住手势,获取屏幕上手指的坐标,将这些坐标转换为网页的坐标系,最后在该位置查找HTML元素。
因此,您计划使用上下文菜单实现自己的弹出控制器 - 很好,我不会涉及这个问题,我假设您知道如何做到这一点。
你的问题似乎是,如何将UIWebView中的长按手势转换为网页的坐标,以找到所选的DOM元素,并将其用作生成弹出菜单的上下文。
我发现的是
this, 具体来说,是使用下面这行代码:
this。
NSString *js = [NSString stringWithFormat:@"document.elementFromPoint(%f, %f).innerHTML", touchPoint.x, touchPoint.y];
这似乎是你需要找到刚刚被长按的什么元素的JS代码,当然你需要进行一些计算来确定它是否是一个链接,并从那里执行上下文菜单,但这不是我研究过的内容。
进一步的想法:
可能最简单的方法是将UILongPressGestureRecognizer
附加到您的UIWebView上(可以在nib中轻松完成),并确保“发送操作”指向ViewController上适当的IBAction。 (我想您也可以使用委托出口,但我从未需要这样做。)
无论如何,您可以使用手势识别器的
locationOfTouch:inView:方法,您可能想要使用的视图将是UIWebView的内容视图,我相信您可以使用类似
myWebView.scrollView.subviews[0]
的东西获取它(如果您没有使用新的数组索引下标,则可以使用objectAtIndex变体)。
无论如何,我认为我已经提供了足够的答案来回答您的问题。
编辑:
好的,你仍然在遇到困难,所以我制作了一个测试项目并使其正常工作。其中一个略微烦人的事情是,WebKit在DOM中的对象周围添加了一个“缓冲”区域,这意味着如果您轻微地触摸链接旁边,它仍然会突出显示,但是当您使用JS命令elementFromPoint
时,它不会这样做,因此您必须更加小心地触发使用此方法的弹出窗口。但是,它有效。
我创建了一个带有“单视图”模板的空白项目,并将UIWebView
放入xib中,将其delegate
输出指向File's Owner。然后我将UILongPressGestureRecognizer
放入xib中,附加到UIWebView。我将其delegate
设置为File's Owner,并将其selector
输出设置为File's Owner中的longPressDetected
IBAction。我还在Interface Builder中取消选中了识别器属性中的“在视图中取消”。
以下是视图控制器的代码。
接口:
#import <UIKit/UIKit.h>
@interface WVTViewController : UIViewController <UIWebViewDelegate, UIGestureRecognizerDelegate>
@property (nonatomic, weak) IBOutlet UIWebView *myWebView;
@property (nonatomic) BOOL didFirstLoad;
- (IBAction)longPressDetected:(id)sender;
@end
实现:
#import "WVTViewController.h"
@interface WVTViewController ()
@end
@implementation WVTViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL *theURL = [NSURL URLWithString:@"http://www.google.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:theURL];
[self.myWebView loadRequest:request];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
if (!self.didFirstLoad) {
[webView stringByEvaluatingJavaScriptFromString:@"document.body.style.webkitTouchCallout='none';"];
}
}
- (IBAction)longPressDetected:(UILongPressGestureRecognizer *)sender
{
if (sender.state == UIGestureRecognizerStateBegan) {
NSLog(@"Long press detected.");
CGPoint webViewCoordinates = [sender locationInView:self.myWebView];
NSLog(@"WebView coordinates are: %@", NSStringFromCGPoint(webViewCoordinates));
NSString *locatorString = [NSString stringWithFormat:@"document.elementFromPoint(%f, %f).innerHTML", webViewCoordinates.x, webViewCoordinates.y];
NSString *result = [self.myWebView stringByEvaluatingJavaScriptFromString: locatorString];
NSLog(@"Element Found: %@", result);
}
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
@end
如我所说,我测试了上述代码并且它运行正常。你当然可以改变你的JS并使用一些其他的东西,比如tagName
或href
或任何你喜欢的东西。可能需要进行多个检查以完成你想要做的事情,可能需要使用排队的JS命令(这可能有点蠢),除非你能将DOM对象JSON字符串化,将其传回Objective-C,转换为本机对象并在该环境中执行你的检查--但是,我不是JS专业人士,也不打算调查这个。
作为一条注释,我有点惊讶于
elementFromPoint
的坐标是 UIWebView 中的触摸坐标。我已经编写了一整段代码来迭代
myWebView.scrollView.subviews
并找到内容视图,然后在该视图上调用
locationOfTouch:inView:
。但是我得到了奇怪的行为,所以我凭直觉使用了 webview 坐标,即使在我向侧面和向下滚动时,它也可以正常工作,即使在一个大的网页上。我怀疑在 webview 内部有一些由苹果程序设计的行为会转换这些坐标。可能 JS 的坐标系统会根据内容视图在 scrollview 内部移动的方式而改变 - 这对我来说是最有意义的。