Подтвердить что ты не робот

Работает ли UIGestureRecognizer на UIWebView?

Я пытаюсь получить 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 и вставив веб-просмотр в свой nib. Их кратный код работает повсюду, но внутри области веб-просмотра.

4b9b3361

Ответ 1

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

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

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

Редактировать:

Вы можете посмотреть в 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 видно, что они устанавливают очередь и таймер для отправки сообщений. В зависимости от вашего использования, вам может потребоваться сделать то же самое. Есть другие вопросы по этой теме.

Вот документация по обработке событий. В моем случае я добавил слушателей событий в 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 для некоторых вещей.

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, с которым я работал, не было никаких интерактивных элементов, кроме одной или двух ссылок.

Ответ 2

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

Один из вариантов - реализовать протокол UIGestureRecognizerDelegate и реализовать метод gestureRecognizer: shouldRecognizeSimultaneousWithGestureRecognizer. Верните YES из этого метода для других жестов касания. Таким образом вы получите вызов обработчика крана, и веб-представление все равно получит его вызов.

Смотрите это на форумах Apple dev.

Ответ 3

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

- (void)viewDidLoad 
{      
    [super viewDidLoad];

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

    // view is your UIViewController 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

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

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];

Ответ 5

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

Ответ 6

Другой способ - создать прозрачную 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];

Ответ 7

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

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