UIScrollView трогает против прикосновений - PullRequest
7 голосов
/ 18 мая 2009

Пожалуйста, кто-нибудь может помочь разобраться с нубом? Я разместил эту проблему на различных форумах и не получил ответов, в то время как многие поиски других ответов вызвали stackOverflow, поэтому я надеюсь, что это именно то место.

У меня есть BeachView.h (подкласс UIScrollView, изображение песчаного пляжа) со случайным числом Stone.h (подкласс UIImageView, случайный PNG камня, userInteractionEnabled = YES для принятия касаний) .

Если пользователь касается и движется по пляжу, он должен прокручиваться. Если пользователь касается камня, он должен вызвать метод "touchedStone". Если пользователь нажимает на пляж, где нет камня, он должен вызвать метод "touchedBeach".

Теперь я понимаю, что это звучит очень просто. Все и все говорят мне, что если в UIScrollView есть что-то, что принимает прикосновения, то оно должно передать ему управление. Поэтому, когда я касаюсь и перетаскиваю, он должен прокручиваться; но если я постучу, и он на камне, он должен игнорировать пляжные постукивания и принимать каменные постукивания, да?

Однако, похоже, что оба представления принимают нажатие и вызывают оба элемента touchedStone И touchedBeach. Кроме того, сначала происходит нажатие на пляж, поэтому я даже не могу вставить флаг типа «если touchchedStone, то не запускать touchedBeach».

Вот некоторый код. На BeachView.m


- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
     if (self.decelerating) { didScroll = YES; }
        else { didScroll = NO; }

     UITouch *touch = [[event allTouches] anyObject];
     CGPoint touchLocation = [touch locationInView:touch.view];
     NSLog(@"touched beach = %@", [touch view]);
     lastTouch = touchLocation;
     [super touchesBegan:touches withEvent:event];
}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
     didScroll = YES;
     [super touchesMoved:touches withEvent:event];
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
     if (didScroll == NO && isPaused == NO) { 
          [self touchedBeach:YES location:lastTouch];
     }
     [super touchesEnded:touches withEvent:event];
}

On Stone.m


-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
     [parent stoneWasTouched]; // parent = ivar pointing from stone to beachview
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
     UITouch *touch = [[event allTouches] anyObject];
     CGPoint touchLocation = [touch locationInView:touch.view];
     NSLog(@"touched stone = %@", [touch view]);
     [parent touchedStone:YES location:touchLocation];
}

После каменного постукивания My NSLog выглядит так:


Touched beach = <BeachView: 0x1276a0>
ran touchedBeach
Touched Stone = <Stone: 0x1480c0>
ran touchedStone

Так что на самом деле работает оба. Что еще более странно, если я возьму touchesBegan и touchesEnded из Stone.m, но оставлю userInteractionEnabled = YES, beachView регистрирует оба касания сам, но возвращает Stone как вид, которого он коснулся (второй раз).


Touched beach = <BeachView: 0x1276a0>
ran touchedBeach
Touched beach = <Stone: 0x1480c0>
ran touchedBeach

Итак, ПОЖАЛУЙСТА, я пытался разобраться в этом в течение нескольких дней. Как сделать так, чтобы звонки по касанию только касались Камня и звонки по касанию только касались пляжа? Куда я иду не так?

Ответы [ 4 ]

3 голосов
/ 03 ноября 2009

Верно, iPhone SDK 3.0 и выше, не касайтесь методов подклассов -touchesBegan: и - touchesEnded: **UIScrollview**. Вы можете использовать разные методы touchesShouldBegin и touchesShouldCancelInContentView.

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

В вашем подклассе UIScrollView переопределите метод hitTest следующим образом:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {

  UIView *result = nil;
  for (UIView *child in self.subviews)
    if ([child pointInside:point withEvent:event])
      if ((result = [child hitTest:point withEvent:event]) != nil)
        break;

  return result;
}

Это передаст вам подкласс этого касания, однако вы не можете отменить касания до UIScrollView суперкласса.

2 голосов
/ 18 мая 2009

До iPhone OS 3.0 метод hitTest: withEvent: UIScrollView всегда возвращает self, чтобы он получал UIEvent напрямую, только перенаправляя его в соответствующее подпредставление, если и когда он определяет, что он не связан с прокруткой или масштабированием.

Я не могу прокомментировать iPhone OS 3.0, так как он под NDA, но посмотрите ваши «Замечания к выпуску iPhone SDK для iPhone OS 3.0 beta 5»:)

Если вам нужно нацелиться на версию до 3.0, вы можете переопределить hitTest: withEvent: в BeachView и установить флаг, чтобы игнорировать следующее касание пляжа, если CGPoint действительно находится в камне.

Но пытались ли вы просто переместить ваши вызовы в [super touch *: withEvent:] с конца переопределенных методов на начало? Это может привести к тому, что каменный стук произойдет первым.

0 голосов
/ 27 ноября 2013

Это может быть связано с ошибкой в ​​iOS7, просмотрите мою проблему (отчет об ошибке отправлен)

Подкласс UIScrollView изменил поведение в iOS7

0 голосов
/ 19 ноября 2013

У меня была похожая проблема с simpleView, и она добавлялась к scrollView, и всякий раз, когда я касался simpleView, scrollView использовался для получения прикосновения, а вместо simpleView - scrollView переехал. Чтобы избежать этого, я отключил прокрутку scrollView, когда пользователь коснулся simpleView, в противном случае прокрутка включена.

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {

    UIView *result = [super hitTest:point withEvent:event] ;
    if (result == simpleView)
    {
        scrollView.scrollEnabled = NO ;
    }
    else
    {
        scrollView.scrollEnabled = YES ;
    }

    return result ;

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