Работает ли UIGestureRecognizer с UIWebView? - PullRequest
40 голосов
/ 26 мая 2010

Я пытаюсь заставить UIGestureRecognizer работать с UIWebview, который является подпредставлением UIScrollView. Это звучит странно, но когда у меня numberOfTouchesRequired установлен на 2, селектор срабатывает, но когда numberOfTouchesRequired установлен на один, селектор не срабатывает.

Вот мой код:

UITapGestureRecognizer *tap1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(select1:)];
    tap1.numberOfTouchesRequired = 2;
    tap1.numberOfTapsRequired = 1;
    tap1.delegate = self;
    [self.ans1WebView addGestureRecognizer:tap1];
    [tap1 release];

- (void) select1:(UILongPressGestureRecognizer *)sender {
    //Do Stuff
}

Я подтвердил это, используя образец Apple для UIGestureRecognizer и вставив веб-просмотр в их перо. Их код нажатия работает везде, но внутри области веб-просмотра.

Ответы [ 7 ]

67 голосов
/ 26 мая 2010

Из того, что я видел, UIWebView плохо взаимодействует с другими. Для распознавателей жестов вы можете попробовать вернуть YES из:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;

Я должен был быть обратно совместимым с 3.0, поэтому я закончил всю обработку жестов с помощью Javascript внутри UIWebView. Не очень хорошее решение, но оно сработало для моих нужд. Мне удалось запечатлеть долгое нажатие на элемент, а также нажать, пролистать, ущипнуть и повернуть. Конечно, я использовал только локальный контент.

Edit:

Вы можете посмотреть в PhoneGap пример отправки сообщений делегату UIWebView. Одним словом, вы используете document.location = "myscheme:mycommand?myarguments", а затем анализируете команду и аргументы из этого обратного вызова делегата:

-(BOOL) webView:(UIWebView *)inWeb shouldStartLoadWithRequest:(NSURLRequest *)inRequest navigationType:(UIWebViewNavigationType)inType {
  if ( [[[inRequest URL] absoluteString] hasPrefix:@"myscheme:"] ) {
    //.. parse arguments
    return NO;
  }
}

В коде PhoneGap видно, что они настроили очередь и таймер для отправки сообщений. В зависимости от вашего использования, вам может потребоваться сделать то же самое. На эту тему есть другие вопросы по SO.

Вот документация Обработка событий . В моем случае я добавил слушателей событий в document из <body onload="myloader();">

function myloader() {
    document.addEventListener( 'touchcancel' , touch_cancel , false );
    document.addEventListener( 'touchstart' , touch_start , false );
    document.addEventListener( 'touchmove' , touch_move , false );
    document.addEventListener( 'touchend' , touch_end , false );
};

Фактическая обработка событий во многом зависит от ваших потребностей. Каждый обработчик события получит TouchEvent со свойством touch, где каждый элемент имеет значение Touch . Вы можете записать время начала и местоположение в вашем обработчике сенсорного запуска. Если касания перемещаются далеко или проходит неправильное количество времени, это не длинное касание.

WebKit может попытаться обработать длинное касание, чтобы начать выделение и копировать. В вашем обработчике событий вы можете использовать event.preventDefault();, чтобы остановить поведение по умолчанию. Я также нашел свойство -webkit-user-select:none css удобным для некоторых вещей.

var touch = {};
function touch_start( event /*TouchEvent*/ {
  event.preventDefault();
  touch = {};
  touch.startX = event.touches.item(0).pageX;
  touch.startY = event.touches.item(0).pageY;
  touch.startT = ( new Date() ).getTime();
}

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

Как видите, это не быстрый ответ на вашу проблему. Я очень доволен результатами, которые получил. В HTML, с которым я работал, не было никаких интерактивных элементов, кроме одной или двух ссылок.

45 голосов
/ 22 октября 2010

UIWebView имеет свои собственные частные представления, к которым также прикреплены распознаватели жестов. Следовательно, правила приоритета препятствуют правильной работе любых распознавателей жестов, добавленных в UIWebView.

Одним из вариантов является реализация протокола UIGestureRecognizerDelegate и реализация метода gestRecognizer: shouldRecognizeSim одновременноuallyWithGestureRecognizer. Верните ДА из этого метода для других жестов касания. Таким образом, вы получите вызов вашего обработчика крана, а веб-представление все равно получит его.

См. на форумах разработчиков Apple .

13 голосов
/ 16 сентября 2013

Это несколько взломанное решение, но оно работает. UIWebView имеет много внутренних распознавателей жестов, к которым вы обычно не можете получить доступ без использования частного API. Однако вы получаете их все бесплатно, когда внедряете gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:. В этот момент вы можете указать всем внутренним UITapGestureRecognizer запускаться только при сбое вашего собственного UITapGestureRecognizer. Вы делаете это только один раз, а затем удаляете делегата из вашего собственного распознавателя жестов. В результате вы все еще можете выполнять панорамирование и прокрутку веб-представления, но он больше не будет получать никаких (однократных) жестов.

- (void)viewDidLoad 
{      
    [super viewDidLoad];

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];

    // view is your UIViewController's view that contains your UIWebView as a subview
    [self.view addGestureRecognizer:tap];

    tap.delegate = self;
}

- (void)handleTapGesture:(UITapGestureRecognizer *)gestureRecognizer
{
    NSLog(@"tap!");

    // this is called after gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: so we can safely remove the delegate here
    if (gestureRecognizer.delegate) {
        NSLog(@"Removing delegate...");
        gestureRecognizer.delegate = nil;
    }
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    if ([otherGestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
        [otherGestureRecognizer requireGestureRecognizerToFail:gestureRecognizer];

        NSLog(@"added failure requirement to: %@", otherGestureRecognizer);
    }

    return YES;
}

Наслаждайтесь!

4 голосов
/ 28 мая 2013

У меня была такая же проблема. Это решение работало для меня:

1) Обязательно добавьте протокол в интерфейс: UIGestureRecognizerDelegate, например:

@interface ViewController : UIViewController <SlideViewProtocol, UIGestureRecognizerDelegate>

2) Добавить эту строку кода

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES
}

3) Настройка жеста

UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(nextSlide)];
swipeGesture.numberOfTouchesRequired = 1;
swipeGesture.direction = (UISwipeGestureRecognizerDirectionLeft);
swipeGesture.cancelsTouchesInView = YES; [swipeGesture setDelegate:self];
[self.view addGestureRecognizer:swipeGesture];
3 голосов
/ 26 октября 2013
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer {
    return YES;
}
2 голосов
/ 06 сентября 2013

Другой способ - поместить прозрачную UIButton поверх UIWebView и обрабатывать нажатия этой кнопки. В некоторых случаях это может быть хорошим решением.

UIWebView webView = [UIWebView new];
//...

UIButton *transparentButton = [UIButton buttonWithType:UIButtonTypeCustom];
[transparentButton addTarget:self action:@selector(buttonTapped) forControlEvents:(UIControlEventTouchUpInside)];
transparentButton.frame = webView.frame;
transparentButton.layer.backgroundColor = [[UIColor clearColor] CGColor];
[self.view transparentButton];
1 голос
/ 03 сентября 2010

Вы также можете найти мой ответ здесь полезным. Это рабочий пример обработки жеста повышения в javascript UIWebView.

(Вы можете сообщить о событиях обратно в Objective-C, если хотите. См. мой ответ здесь .)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...