在文本区域/输入UIWebview中禁用长按菜单 [英] Disable long press menu in text area/input UIWebview

查看:126
本文介绍了在文本区域/输入UIWebview中禁用长按菜单的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这似乎是这里讨论最频繁的主题,但是我找不到真正有效的解决方案.我发布这个问题是为了分享我找到的解决方案,并希望找到更好/更干净的解决方案

This seems to be one of the most frequently discussed topics here but I couldn't find a solution which actually works. I'm posting this question to share a solution which I found as well as hoping to find a better/cleaner solution

情况说明:

  • 我的应用程序中有一个UIWebview

  • There is a UIWebview in my application

Web视图中有文本输入/区域

There is text input/area in the webview

长按文本区域/输入会弹出一个上下文菜单,其中包含剪切",复制",定义"等.

Long pressing on the text area/input brings up a context menu with 'cut', 'copy', 'define' etc.

我们需要在不禁用用户输入的情况下禁用此菜单.

We need to disable this menu without disabling user input.

到目前为止我尝试过的 (无效的内容):

What I've tried so far (Stuff that doesn't work) :

此解决方案告诉我们将canPerformAction:withSender:添加到UIWebview的子类或UIWebview的委托中.

This solution tells us to add canPerformAction:withSender: to either subclass of UIWebview or in a delegate of UIWebview.

- (BOOL) canPerformAction:(SEL)action withSender:(id)sender
{
 if (action == @selector(defineSelection:))
 {
    return NO;
 }
 else if (action == @selector(translateSelection:))
 {
    return NO; 
 }
 else if (action == @selector(copy:))
 {
    return NO;
 }

return [super canPerformAction:action withSender:sender];
}

不起作用,因为未为显示的菜单项调用此类中的canPerformAction:. 由于sharedMenuController与Responder链中的第一个响应者进行交互,因此在容器中实现canPerformAction会跳过select和selectAll,因为它们已经由子菜单处理了.

Does not work because the canPerformAction: in this class is does not get called for menu items displayed. Since the sharedMenuController interacts with the first responder in the Responder chain, implementing canPerformAction in the container skipped select and selectAll because they had already been handled by a child menu.

将以下内容添加到CSS:

Add the following to CSS:

html {
    -webkit-user-select: none;
    -webkit-touch-callout: none;
    -webkit-tap-highlight-color:rgba(0,0,0,0);
}

这确实适用于图像和超链接,但不适用于输入. :(

This does work on images and hyperlinks but not on inputs. :(

推荐答案

第一个解决方案不起作用的根本原因是名为UIWebBrowserView的子视图.对于在上下文菜单中显示的任何action来说,这似乎都是其canPerformAction返回true的视图.

The root cause of the first solution not working is the subview called UIWebBrowserView. This seems to be the view whose canPerformAction returns true for any action displayed in the context menu.

由于此UIWebBrowserView是私有类,我们不应尝试对其进行子类化(因为它会导致您的应用被拒绝).

Since this UIWebBrowserView is a private class we shouldn't try to subclass it (because it will get your app rejected).

所以我们要做的是制作另一个称为mightPerformAction:withSender:的方法,例如so-

So what we do instead is we make another method called mightPerformAction:withSender:, like so-

- (BOOL)mightPerformAction:(SEL)action withSender:(id)sender {


NSLog(@"******Action!! %@******",NSStringFromSelector(action));


  if (action == @selector(copy:))
  {
      NSLog(@"Copy Selector");
      return NO;
  }
  else if (action == @selector(cut:))
  {
      NSLog(@"cut Selector");
      return NO;
  }
  else if (action == NSSelectorFromString(@"_define:"))
  {
      NSLog(@"define Selector");
      return NO;
  }
  else if (action == @selector(paste:))
  {
      NSLog(@"paste Selector");
      return NO;
  }
  else
  {
      return [super canPerformAction:action withSender:sender];
  }


}

并添加另一种方法以将mayPerformAction:withSender:替换为mayPerformAction:withSender:

and add another method to replace canPerformAction:withSender: with mightPerformAction:withSender:

- (void) replaceUIWebBrowserView: (UIView *)view
{

//Iterate through subviews recursively looking for UIWebBrowserView
for (UIView *sub in view.subviews) {
    [self replaceUIWebBrowserView:sub];
    if ([NSStringFromClass([sub class]) isEqualToString:@"UIWebBrowserView"]) {

        Class class = sub.class;

        SEL originalSelector = @selector(canPerformAction:withSender:);
        SEL swizzledSelector = @selector(mightPerformAction:withSender:);

        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(self.class, swizzledSelector);

        //add the method mightPerformAction:withSender: to UIWebBrowserView
        BOOL didAddMethod =
        class_addMethod(class,
                        originalSelector,
                        method_getImplementation(swizzledMethod),
                        method_getTypeEncoding(swizzledMethod));
        //replace canPerformAction:withSender: with mightPerformAction:withSender:
        if (didAddMethod) {
            class_replaceMethod(class,
                                swizzledSelector,
                                method_getImplementation(originalMethod),
                                method_getTypeEncoding(originalMethod));

        } else {

            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    }
}
}

最后在ViewController的viewDidLoad中调用它:

And finally call it in the viewDidLoad of the ViewController:

[self replaceUIWebBrowserView:self.webView];

注意:将#import <objc/runtime.h>添加到您的viewController中,然后错误(方法)将不会显示.

Note: Add #import <objc/runtime.h> to your viewController then error(Method) will not shown.

注意:我正在使用NSSelectorFromString方法来避免在审核过程中检测到私有API选择器.

Note: I am using NSSelectorFromString method to avoid detection of private API selectors during the review process.

这在使用Xcode 5的iOS7中似乎可以正常工作,如果有人可以在其中找到任何问题,请让我知道我可以对其进行改进..

This seems to be working fine in iOS7 with Xcode 5, if anyone can find any issues in this please let me know how I can improve it..

这篇关于在文本区域/输入UIWebview中禁用长按菜单的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆