Когда пользователь долго нажимает ссылку, появляется контроллер предупреждений с опциями:
- Открытым
- Открыть в новой вкладке
- Копировать
На данный момент есть две проблемы:
Если пользователь выполняет долгое нажатие до того, как 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);
}];
}
Во-вторых,
UILongPressGestureRecognizer добавлен в WKWebView и реализован таким образом, что он находит атрибуты элементов на основе местоположения касания.
- (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, которое имеет значение ДА, когда был представлен контроллер предупреждений, и НЕТ, когда он был отклонен.
- (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:
Если я полностью удалю свою реализацию (все 3 шага) и позволю контроллеру предупреждений по умолчанию срабатывать каждый раз, когда я долго нажимаю ссылку, вторая проблема будет решена.
В контроллере предупреждений Apple есть что-то, что не позволяет WKWebView перемещаться после того, как вы уберете палец.