2015-10-20 6 views
16

Требования

У меня есть WKWebView и хотел бы, чтобы удалить пункты меню системы (Копировать, Определить, делись ...) из меню Edit и представить мои собственные.Отключить все меню UIMenuController редактировать в WKWebView

Я ориентируюсь на iOS 8 и 9. В настоящее время я тестирую симулятор Xcode 7.0.1 (iOS 9) и мой iPhone 6 под управлением iOS 9.0.2.

Стандартный метод не работает

Я знаю, стандартным способом достижения этого является подклассов WKWebView и реализации -canPerformAction:withSender:. Однако я обнаружил, что с WKWebView-canPerformAction:withSender: не вызывается для действий copy: или define:. Это, по-видимому, известная ошибка (WKWebView and UIMenuController).

Пример приложения: https://github.com/dwieringa/WKWebViewCustomEditMenuBug

@implementation MyWKWebView 

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender 
{ 
    NSLog(@"ACTION: %@", NSStringFromSelector(action)); 

    if (action == @selector(delete:)) 
    { 
     // adding Delete as test (works) 
     return YES; 
    } 

    // trying to remove everything else (does NOT work for Copy, Define, Share...) 
    return NO; 
} 

- (void)delete:(id)sender 
{ 
    NSLog(@"Delete menu item selected"); 
} 

@end 

Выход: (обратите внимание, не copy: или define: действие)

2015-10-20 12:28:32.864 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: cut: 
2015-10-20 12:28:32.865 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: select: 
2015-10-20 12:28:32.865 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: selectAll: 
2015-10-20 12:28:32.865 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: paste: 
2015-10-20 12:28:32.866 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: delete: 
2015-10-20 12:28:32.866 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _promptForReplace: 
2015-10-20 12:28:32.866 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _transliterateChinese: 
2015-10-20 12:28:32.867 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _showTextStyleOptions: 
2015-10-20 12:28:32.907 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _addShortcut: 
2015-10-20 12:28:32.908 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _accessibilitySpeak: 
2015-10-20 12:28:32.908 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _accessibilitySpeakLanguageSelection: 
2015-10-20 12:28:32.908 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _accessibilityPauseSpeaking: 
2015-10-20 12:28:32.909 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: makeTextWritingDirectionRightToLeft: 
2015-10-20 12:28:32.909 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: makeTextWritingDirectionLeftToRight: 

Запланированные Обход

Мое желание теперь полностью скрыть меню редактирования и замены он с пользовательским меню, используя QBPopupMenu.

Моя проблема заключается в том, что я не смог найти способ скрыть или отключить стандартное меню «Правка». Я нашел несколько предложений, чтобы скрыть его [UIMenuController sharedMenuController].menuVisible = NO; по адресу UIMenuControllerWillShowMenuNotification, но я не смог заставить его работать. Он не влияет на WillShowMenu. Я могу скрыть его в DidShowMenu, но к этому моменту уже слишком поздно, и я получаю флеш меню.

Я также попытался найти его за пределами видимой области, используя [[UIMenuController sharedMenuController] setTargetRect:CGRectMake(0, 0, 1, 1) inView:self.extraView];, но опять же с WillShowMenu не влияет, и с DidShowMenu уже слишком поздно.

Эксперименты доступны здесь: https://github.com/dwieringa/WKWebViewEditMenuHidingTest

Что мне не хватает? Есть ли другой способ отключить или скрыть стандартное меню редактирования для WKWebView?

+0

Из любопытства вы подали сообщение об ошибке с Apple, для этого? – Ryan

+0

@ Ryan, еще нет. Спасибо за ваш ответ ниже. Я просто попробовал, и я все еще вижу меню, когда я долго нажимаю на текст под iOS 9 на своем iPhone 6. Пробовали ли вы его с WKWebView на iOS? Я проверил с веб-инспектором, что новая настройка CSS применяется к телу. – davew

+0

@davew какой-нибудь успех с этим? –

ответ

0

Один из способов, который я использовал, - просто отключить меню с помощью CSS. Свойство CSS называется -webkit-touch-callout: none;. Вы можете применить его к элементу верхнего уровня и отключить его для всей страницы или любого дочернего элемента и отключить ее с большей точностью. Надеюсь, это поможет.

4

Основываясь на вашем обходного пути, я узнал, что:

-(void)menuWillShow:(NSNotification *)notification 
{ 
    NSLog(@"MENU WILL SHOW"); 

    dispatch_async(dispatch_get_main_queue(), ^{ 
     [[UIMenuController sharedMenuController] setMenuVisible:NO animated:NO]; 
    }); 

} 

помешает меню мигания 90% времени .. До сих пор не достаточно хорошо, но это еще один обходной путь, прежде чем мы нашли достойное решение.

+0

Я в порядке с этим.+1 –

+1

Не уверен, что это изменилось с тех пор, как вы отправили, но для меня это работает (как и в случае, меню никогда не отображается) 100% времени после попытки не менее 30 раз :) –

+0

Я даже не работаю этот проект больше, но это хорошо знать :) –

1

Я исправил его после некоторого наблюдения.

В -canPerformAction:withSender: Я возвращаю NO для _share и _define вариантов, поскольку они мне не нужны в моем проекте.Он работает как ожидается при выборе слова в первый раз, но отображает варианты со второго раза.

Простой исправление: Добавить [self becomeFirstResponder]; в tapGuesture или сенсорный делегированных методов

-(BOOL)canPerformAction:(SEL)action withSender:(id)sender { 
    SEL defineSEL = NSSelectorFromString(@"_define:"); 
    if(action == defineSEL){ 
     return NO; 
    } 

    SEL shareSEL = NSSelectorFromString(@"_share:"); 
    if(action == shareSEL){ 
     return NO; 
    } 
    return YES; 
} 

// Tap gesture delegate method 
- (void)singleTap:(UITapGestureRecognizer *)sender { 
    lastTouchPoint = [sender locationInView:self.webView]; 
    [self becomeFirstResponder]; //added this line to fix the issue// 
} 
6

Попробуйте сделать ваш контроллер представления стать первым ответчиком и остановить его подать в отставку первый ответчик

- (BOOL)canResignFirstResponder { 
    return NO; 
} 

- (BOOL)canBecomeFirstResponder { 
    return YES; 
} 

https://github.com/dwieringa/WKWebViewEditMenuHidingTest/pull/1

+0

Кажется, он решил это для меня. –

+0

Это правильный ответ. Я использовал то же самое в swift 3, xcode 8.2 и работал нормально. Вот быстрый код. \t переопределение вар canBecomeFirstResponder: Bool { \t \t возвращающие \t} \t \t переопределение вар canResignFirstResponder: Bool { \t \t возвращение ложным \t} – Vijay

+0

Не работает для WkWebView –

1

Эй ребята, потратив на это несколько часов, я нашел грязное решение с коэффициентом успеха 100%.

логика есть; обнаружить, когда UIMenuController показал и обновил его.

В вашем ViewController (содержащем WKWebView) добавить UIMenuControllerDidShowMenu observer в viewDidLoad() следующим образом;

override func viewDidLoad() { 
super.viewDidLoad() 
     NotificationCenter.default.addObserver(
         self, 
         selector: #selector(uiMenuViewControllerDidShowMenu), 
         name: NSNotification.Name.UIMenuControllerDidShowMenu, 
         object: nil) 
} 

Не забудьте удалить наблюдателя в deinit.

deinit { 
    NotificationCenter.default.removeObserver(
         self, 
         name: NSNotification.Name.UIMenuControllerDidShowMenu, 
         object: nil) 
    } 

И в вашем селекторе, обновить UIMenuController так:

func uiMenuViewControllerDidShowMenu() { 
     if longPress { 
      let menuController = UIMenuController.shared 
      menuController.setMenuVisible(false, animated: false) 
      menuController.update() //You can only call this and it will still work as expected but i also call setMenuVisible just to make sure. 
     } 
    } 

В вашем ViewController, которые когда-либо называет UIMenuController, этот метод будет вызван. Я разрабатываю приложение для браузера, поэтому у меня есть также searchBar, и пользователь может захотеть вставить туда текст. Из-за этого я обнаруживаю longPress в своем веб-просмотре и проверяю, вызван ли UIMenuController WKWebView.

Это решение будет вести себя как в gif. Вы можете увидеть меню в течение секунды, но вы не можете нажать на него. Вы можете попытаться коснуться его, прежде чем он исчезнет, ​​но вам это не удастся. Попробуйте и скажите мне свои результаты.

Надеюсь, это поможет кому-то.

Cheers.

enter image description here

+0

привет, как мы можем сделать это в объективе c? – coder

+0

Решение Paulo Cesar позволяет отображать меню для этой доли секунды: https://stackoverflow.com/a/34228687/374516 –

1

Эта ошибка на самом деле вызвана действиями добавляемого в WKContentView, который является частным классом. Вы можете добавить расширение UIView работать вокруг него, как это:

import UIKit 

extension UIView { 

    open override class func initialize() { 
     guard NSStringFromClass(self) == "WKContentView" else { return } 

     swizzleMethod(#selector(canPerformAction), withSelector: #selector(swizzledCanPerformAction)) 
    } 

    fileprivate class func swizzleMethod(_ selector: Selector, withSelector: Selector) { 
     let originalSelector = class_getInstanceMethod(self, selector) 
     let swizzledSelector = class_getInstanceMethod(self, withSelector) 
     method_exchangeImplementations(originalSelector, swizzledSelector) 
    } 

    @objc fileprivate func swizzledCanPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { 
     return false 
    } 
} 
+0

Это решение не компилируется в Swift 4. Появляется следующее сообщение об ошибке: «Method» initialize () 'определяет метод класса Objective-C' initialize ', который не разрешен Swift' –

0

Прагма знак - WKNavigationDelegate

- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation { 
    // Add: 
    // Disable LongPress and Selection, no more UIMenucontroller 
    [self.wkWebView evaluateJavaScript:@"document.documentElement.style.webkitUserSelect='none'" completionHandler:nil]; 
    [self.wkWebView evaluateJavaScript:@"document.documentElement.style.webkitTouchCallout='none'" completionHandler:nil]; } 
Смежные вопросы