新答案:
看起来这就是我们想要的,在这里:
https://stackoverflow.com/a/3198220/700471
旧答案:
好的,经过一番研究,这是交易:
您在问题中的描述似乎准确:
首先,你真的不能在
标准上下文菜单的默认菜单。但是你可以关掉
使用特定 CSS 属性的上下文菜单。所以解决方案
将关闭默认菜单并实现您自己的
刮。要实现您自己的上下文菜单,您必须首先
抓住制表并按住手势,获取手指的坐标
屏幕,将这些坐标转换为
网页,最后在这个位置寻找 HTML 元素。
所以你打算用上下文菜单实现你自己的弹出框控制器——好吧,我根本不会讨论这个,我假设你知道怎么做。
您的问题似乎是,您如何在 UIWebView 中进行长按手势并将其转换为网页的坐标以查找所选的 DOM 元素,并将其用作上下文生成弹出菜单。
我发现的是this,特别是this,这行代码:
NSString *js = [NSString stringWithFormat:@"document.elementFromPoint(%f, %f).innerHTML", touchPoint.x, touchPoint.y];
这看起来像你需要弄清楚 what 元素刚刚被长按的 JS,当然你需要做一些图形来查看它是否是一个链接和从那里执行你的上下文菜单,但这不是我研究过的。
一些进一步的想法:
可能最简单的方法是将UILongPressGestureRecognizer 附加到您的 UIWebView(这可以在 nib 中轻松完成)并确保“Sent Action”指向 ViewController 上的适当 IBAction。 (我想你也可以使用委托出口,但我从来不需要这样做。)
在任何情况下,您都可以使用手势识别器的 locationOfTouch:inView: 方法,您可能想要使用的视图将是 UIWebView 的内容视图,我相信您可以使用类似 myWebView.scrollView.subviews[0] (或objectAtIndex: 如果你没有使用新的数组索引下标的变化)。
无论如何,我想我已经提供了足够的答案来回答你的问题。
编辑:
好的,所以你仍然有这个问题,所以我去做了一个测试项目并让它工作。对此有点烦人的一点是,WebKit 以某种方式在 DOM 中的对象周围添加了一个“缓冲区”区域,这意味着如果您在 next to 稍微触摸一个链接,它仍然会突出显示,但是当您使用JS 命令elementFromPoint 并没有这样做,所以你必须更仔细地触摸才能使用这种方法触发弹出窗口。但是,它有效。
我使用“单一视图”模板制作了一个空白项目,并将UIWebView 扔到 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 或 href 或任何您喜欢的东西。您尝试执行的操作可能需要进行多次检查,可能使用排队的 JS 命令(这将是蹩脚的),除非您可以对 DOM 对象进行 JSON 字符串化,将其传递回 Objective-C,转换为本机对象并在那个环境中执行你的检查——但是,我不是 JS 专业人士,我不会对此进行调查。
作为说明,我有点惊讶elementFromPoint 的坐标是 UIWebView 本身内的触摸坐标。我已经装配了一整块代码,它遍历myWebView.scrollView.subviews 并找到了内容视图,然后在该视图上调用了locationOfTouch:inView:。但是我的行为很奇怪,所以我预感到我使用了 webview 坐标并且它工作得很好,即使在我被滚动到一边和向下时在一个大网页上也是如此。我怀疑 webview 中的某种 Apple 编程行为可能会转换这些坐标。可能 JS 的坐标系会根据内容视图在滚动视图内的移动方式而改变——这对我来说是最有意义的。