新答案:
看起来这就是我们想要的,这里:
https://stackoverflow.com/a/3198220/700471
旧答案:
好的,经过一番研究,这是交易:
您在问题中描述的内容似乎是准确的:
首先,您确实不能向标准上下文菜单的默认菜单项添加其他菜单项。但是您可以使用某个 CSS 属性关闭上下文菜单。所以解决方案是关闭默认菜单并从头开始实施您自己的菜单。而要实现你自己的上下文菜单,你必须首先捕捉到tab-and-hold手势,获取手指在屏幕上的坐标,将这些坐标转换为网页的坐标系,最后在以下位置查找HTML元素这个位置。
所以你打算用上下文菜单实现你自己的弹出框控制器——好吧,我根本不会涉及到,我会假设你知道如何做到这一点。
您的问题似乎是,您如何在 UIWebView 中采用长按手势并将其转换为网页的坐标以查找所选的 DOM 元素,并将其用作生成弹出框的上下文菜单。
我发现的是这个,特别是这行代码:
NSString *js = [NSString stringWithFormat:@"document.elementFromPoint(%f, %f).innerHTML", touchPoint.x, touchPoint.y];
这看起来像 JS,你需要弄清楚什么元素刚刚被长按,当然你需要做一些图形来查看它是否是一个链接并从那里执行你的上下文菜单,但这不是我调查过的东西。
一些进一步的想法:
可能最简单的方法是将 a 附加UILongPressGestureRecognizer
到您的 UIWebView(这可以在 nib 中轻松完成)并确保“Sent Action”指向 ViewController 上的适当 IBAction。(我想你也可以使用委托出口,但我从来不需要这样做。)
在任何情况下,您都可以使用手势识别器的locationOfTouch:inView:方法,而您可能想要使用的视图将是 UIWebView 的内容视图,我相信您可以使用类似myWebView.scrollView.subviews[0]
(或 objectAtIndex: 变化,如果您没有使用新的数组索引下标)。
无论如何,我想我已经提供了足够的答案来回答你的问题。
编辑:
好的,所以你仍然有这个问题,所以我去做了一个测试项目并让它工作。对此有点烦人的一点是,WebKit 以某种方式在 DOM 中的对象周围添加了一个“缓冲区”区域,这意味着如果您在链接旁边稍微触摸它仍然会突出显示,但是当您使用 JS 命令elementFromPoint
时它不会这样做,因此您必须更仔细地触摸才能使用此方法触发弹出窗口。但是,它有效。
我用“单一视图”模板制作了一个空白项目,并将 aUIWebView
放入 xib 中,将其delegate
出口指向文件所有者。然后我把一个UILongPressGestureRecognizer
放入xib,附加到UIWebView。我将其设置delegate
为文件所有者,并将其selector
出口设置为文件所有者中的longPressDetected
IBAction。我还在 Interface Builder 的识别器属性中取消选中“在视图中取消”。
这是视图控制器的代码。
界面:
//
// WVTViewController.h
// WebViewTest
//
#import <UIKit/UIKit.h>
@interface WVTViewController : UIViewController <UIWebViewDelegate, UIGestureRecognizerDelegate>
@property (nonatomic, weak) IBOutlet UIWebView *myWebView;
@property (nonatomic) BOOL didFirstLoad;
- (IBAction)longPressDetected:(id)sender;
@end
执行:
//
// WVTViewController.m
// WebViewTest
//
#import "WVTViewController.h"
@interface WVTViewController ()
@end
@implementation WVTViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Just load google.
NSURL *theURL = [NSURL URLWithString:@"http://www.google.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:theURL];
[self.myWebView loadRequest:request];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
if (!self.didFirstLoad) {
// Disable the default contextual menu.
[webView stringByEvaluatingJavaScriptFromString:@"document.body.style.webkitTouchCallout='none';"];
}
}
// Called by the gesture recognizer.
- (IBAction)longPressDetected:(UILongPressGestureRecognizer *)sender
{
if (sender.state == UIGestureRecognizerStateBegan) {
NSLog(@"Long press detected.");
CGPoint webViewCoordinates = [sender locationInView:self.myWebView];
NSLog(@"WebView coordinates are: %@", NSStringFromCGPoint(webViewCoordinates));
// Find the DOM element
NSString *locatorString = [NSString stringWithFormat:@"document.elementFromPoint(%f, %f).innerHTML", webViewCoordinates.x, webViewCoordinates.y];
NSString *result = [self.myWebView stringByEvaluatingJavaScriptFromString: locatorString];
NSLog(@"Element Found: %@", result);
}
}
// Necessary or the gesture recognizer won't call the IBAction.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
@end
正如我所说,我测试了上面的代码,它工作正常。你当然可以改变你的 JS 并使用除 之外的东西innerHTML
,例如tagName
orhref
或任何你喜欢的东西。您尝试执行的操作可能需要多次检查,可能使用排队的 JS 命令(这将是蹩脚的),除非您可以对 DOM 对象进行 JSON 字符串化,将其传递回 Objective-C,转换为本机对象和在那个环境中执行你的检查——但是,我不是 JS 专业人士,我不会对此进行调查。
作为说明,我有点惊讶的是,工作的elementFromPoint
坐标是 UIWebView 本身内的触摸坐标。我已经组装了整个代码块,它遍历myWebView.scrollView.subviews
并找到了内容视图,然后调用locationOfTouch:inView:
了该视图。但是我的行为很奇怪,所以我预感到我使用了 webview 坐标并且它工作得很好,即使在我被滚动到一边和向下时在一个大网页上也是如此。我怀疑 webview 中的某种 Apple 编程行为可能会转换这些坐标。可能 JS 的坐标系会根据内容视图在滚动视图内的移动方式而改变——这对我来说是最有意义的。