Когда пользователь долго нажимает на ссылку, появляется предупреждающий контроллер с параметрами:
- Открыть
- Открыть в новой вкладке
- Копировать
В настоящее время существует две проблемы:
-
Если пользователь выполняет длинное нажатие до того, как WKWebView завершит навигацию, появится диспетчер предупреждений по умолчанию (Safari).
-
Если пользователь поднимает свой палец после появления всплывающей анимации, WKWebView каким-то образом регистрирует его как нажатие и переходит к этой ссылке, пока контрольный контроллер все еще отображается на экране.
В этот механизм входят три части.
Во-первых,
После того, как WKWebView завершил навигацию, на страницу будет выведен javascript, который отключит контроллер предупреждений по умолчанию.
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
{
[_webView evaluateJavaScript:@"document.body.style.webkitTouchCallout='none';"
completionHandler:^(id result, NSError *error){
NSLog(@"Javascript: {%@, %@}", result, error.description);
}];
}
Во-вторых,
В WKWebView добавлен UILongPressGestureRecognizer и реализован так, что он находит атрибуты элементов на основе местоположения касания.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
- (void)longPress:(UILongPressGestureRecognizer *)longPressGestureRecognizer
{
if (longPressGestureRecognizer.state == UIGestureRecognizerStateBegan) {
_shouldCancelNavigation = YES;
CGPoint touchLocation = [longPressGestureRecognizer locationInView:_webView];
NSString *javascript = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Javascript" ofType:@"js"]
encoding:NSUTF8StringEncoding
error:nil];
[_webView evaluateJavaScript:javascript
completionHandler:^(id result, NSError *error){
NSLog(@"Javascript: {%@, %@}", result, error.description);
}];
[_webView evaluateJavaScript:[NSString stringWithFormat:@"MyAppGetHTMLElementsAtPoint(%f,%f);", touchLocation.x, touchLocation.y]
completionHandler:^(id result, NSError *error){
NSLog(@"Javascript: {%@, %@}", result, error.description);
NSString *tags = (NSString *)result;
if ([tags containsString:@",A,"]) {
[_webView evaluateJavaScript:[NSString stringWithFormat:@"MyAppGetHREFAttributeAtPoint(%f,%f);", touchLocation.x, touchLocation.y]
completionHandler:^(id result, NSError *error){
NSLog(@"Javascript: {%@, %@}", result, error.description);
NSString *urlString = (NSString *)result;
[_delegate webView:self didLongPressAtTouchLocation:touchLocation URL:[NSURL URLWithString:urlString]];
}];
return;
}
if ([tags containsString:@",IMG,"]) {
[_webView evaluateJavaScript:[NSString stringWithFormat:@"MyAppGetSRCAttributeAtPoint(%f,%f);", touchLocation.x, touchLocation.y]
completionHandler:^(id result, NSError *error){
NSLog(@"Javascript: {%@, %@}", result, error.description);
NSString *urlString = (NSString *)result;
[_delegate webView:self didLongPressAtTouchLocation:touchLocation imageWithSourceURL:[NSURL URLWithString:urlString]];
}];
return;
}
}];
}
}
Наконец,
Метод делегата, который представляет контроллер предупреждения, реализован на основном ViewController.
Моим решением второй проблемы было добавить логическое значение shouldCancelNavigation, которое является YES, когда контроллер предупреждения был представлен, и НЕТ, когда он был уволен.
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
if (_shouldCancelNavigation) {
decisionHandler(WKNavigationActionPolicyCancel);
}
else {
decisionHandler(WKNavigationActionPolicyAllow);
}
}
Интересно, что в Интернете есть много примеров, где ссылки НЕ требуют политического решения. Они просто случаются, и я не могу остановить их.
Пример: http://www.dribbble.com
Источник: http://www.icab.de/blog/2010/07/11/customize-the-contextual-menu-of-uiwebview/comment-page-3/
Источник 2: https://github.com/mozilla-mobile/firefox-ios/pull/61
ИЗМЕНИТЬ
Это решает вторую проблему, но я не уверен, что она не сломает что-то в другом месте.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
if ([otherGestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]) {
otherGestureRecognizer.enabled = NO;
otherGestureRecognizer.enabled = YES;
}
return YES;
}
РЕДАКТИРОВАТЬ 2:
Это действительно создает проблему... Вы больше не можете выбирать текст, так как вышеприведенный код сбрасывает внутренние распознаватели жестов нажатия.
РЕДАКТИРОВАТЬ 3:
Если я полностью удалю свою реализацию (все три шага) и позволю контроллеру предупреждений по умолчанию ударить каждый раз, когда я долгое время нажимаю ссылку, вторая проблема будет решена.
Что-то о контроллере предупреждений Apple, который предотвращает навигацию WKWebView после того, как вы поднимаете палец.