如何在UIWebView中添加弹出按钮

5
当我长按来自UIWebView的任何url中的音乐播放选项时,将打开默认的弹出窗口。 我想在弹出窗口中添加一个按钮...是否有可能做到这一点?
例如,我想添加FETCH按钮。
并且我可以更改默认弹出窗口的功能吗,即下面显示的OPENCOPY
我了解到通过谷歌-首先,您真的不能添加额外的菜单项到标准上下文菜单的默认菜单项中。但是,您可以使用某些CSS属性关闭上下文菜单。因此,解决方案就是关闭默认菜单,从头开始实现自己的菜单。要实现自己的上下文菜单,必须首先捕获选项卡和长按手势,获取手指在屏幕上的坐标,将这些坐标转换为网页的坐标系,最后查找此位置处的HTML元素。

我的回答解决了你的问题吗? - Matt Mc
3个回答

5

新答案:

看起来这就是我们想要的,就在这里:

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中取消选中了识别器属性中的“在视图中取消”。

以下是视图控制器的代码。

接口:

//
//  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并使用一些其他的东西,比如tagNamehref或任何你喜欢的东西。可能需要进行多个检查以完成你想要做的事情,可能需要使用排队的JS命令(这可能有点蠢),除非你能将DOM对象JSON字符串化,将其传回Objective-C,转换为本机对象并在该环境中执行你的检查--但是,我不是JS专业人士,也不打算调查这个。

作为一条注释,我有点惊讶于 elementFromPoint 的坐标是 UIWebView 中的触摸坐标。我已经编写了一整段代码来迭代 myWebView.scrollView.subviews 并找到内容视图,然后在该视图上调用 locationOfTouch:inView:。但是我得到了奇怪的行为,所以我凭直觉使用了 webview 坐标,即使在我向侧面和向下滚动时,它也可以正常工作,即使在一个大的网页上。我怀疑在 webview 内部有一些由苹果程序设计的行为会转换这些坐标。可能 JS 的坐标系统会根据内容视图在 scrollview 内部移动的方式而改变 - 这对我来说是最有意义的。

亚马逊,马特...这个答案对我帮助很大...还有一个问题没有回答,那就是在JavaScript中应该采取什么措施...下面的答案帮助我正确地解决了这个问题。 - SameSung Vs Iphone

2

谢谢,但那个不起作用...我不知道为什么...但我已经做了所有的更改...默认弹出窗口被阻止了,但是根据代码应该显示特定的弹出窗口。 - SameSung Vs Iphone
我制作了一个测试项目并使其正常工作。它使用的代码比此链接中的要少得多。请查看我的答案。 - Matt Mc
发送。虽然在公开场合放置您的电子邮件地址可能不明智...但是,如果有效,请至少接受我的答案😉。 - Matt Mc

0

你可以像这样触发事件:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
  if( navigationType == UIWebViewNavigationTypeLinkClicked )
  {
    // Handle your URL click here (open the popup menu)
    // ...
    return NO;
  }
  return YES;
}

不要忘记委托UIWebView。

这实际上不是问题发布者正在寻找的。 - Matt Mc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接