hitTest возвращает неверный UIView - PullRequest
5 голосов
/ 22 октября 2010

У меня есть иерархия представлений, которая содержит меньшие представления в представлении прокрутки.В каждом представлении могут быть подпредставления, такие как кнопки и т. Д.

По некоторым причинам кнопки в представлении не нажимаются;изучение этого вопроса дополнительно показало, что, хотя представление прокрутки получает событие touchBegan, кнопка не получает.Вызов сообщения hitTest: event: показывает, что кнопка не возвращается, даже если она находится в определенных пределах.

Я включил вывод журнала, описывающий местоположение касания в представлении прокрутки, элемент, возвращаемый из hitTest, местоположение касания, если я вызвал locationInView: использование ожидаемого элемента, и иерархию ожидаемого элемента (скадры напечатаны).Из этого вывода я могу сделать вывод, что кнопка должна была вызвана ...

Кто-нибудь может это объяснить?Я что-то упустил?

touched ({451, 309}) on <VCViewContainersView: 0x4b31ee0; frame = (0 0; 748 1024); transform = [0, 1, -1, 0, 0, 0]; autoresize = W+H; layer = <CALayer: 0x4b32130>> (location in expected item: {17, 7.5})
expected touched item is:
view: <UIButtonLabel: 0x482b920; frame = (32 5; 36 19); text = 'Click'; clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x4831370>>, layer transform: [1, 0, 0, 1, 0, 0]
 view: <UIRoundedRectButton: 0x482c100; frame = (50 50; 100 30); opaque = NO; layer = <CALayer: 0x482c450>>, layer transform: [1, 0, 0, 1, 0, 0]
  view: <UIImageView: 0x480f290; frame = (0 0; 320 255); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x480e840>>, layer transform: [1, 0, 0, 1, 0, 0]
   view: <VCViewContainer: 0x4b333c0; frame = (352 246.5; 320 471.75); layer = <CALayer: 0x4b33d50>>, layer transform: [1, 0, 0, 1, 0, 0]
    view: <UIScrollView: 0x4b32600; frame = (0 0; 1024 748); clipsToBounds = YES; autoresize = W+H; userInteractionEnabled = NO; layer = <CALayer: 0x4b32780>>, layer transform: [1, 0, 0, 1, 0, 0]
     view: <VCViewsContainerView: 0x4b31ee0; frame = (0 0; 748 1024); transform = [0, 1, -1, 0, 0, 0]; autoresize = W+H; layer = <CALayer: 0x4b32130>>, layer transform: [0, 1, -1, 0, 0, 0]
      view: <UIWindow: 0x4b1d590; frame = (0 0; 768 1024); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x4b1d6d0>>, layer transform: [1, 0, 0, 1, 0, 0]

Обновление : Кроме UIWindow и VCViewsContainerView , все представления создаются программно с использованием initWithFrame: или, в случае кнопки, buttonWithType: .VCViewContainer инициализируется с использованием CGRectZero , и когда создается UIImageView , его фрейму присваивается размер изображения + дополнительное пространство для надписей внизу.

Обновление 2 : При вызове [self.layer hitTest: location] с тем же местоположением я получаю слой правильного представления!Что здесь происходит ...?

Ответы [ 3 ]

5 голосов
/ 28 октября 2010

hitTest: withEvent: начинается в окне. Каждое представление проверяет свои подпредставления перед самим тестированием и т. Д. Рекурсивно. Однако если userInteractionEnabled представления имеет значение NO, он возвращает nil из hitTest: withEvent:, без проверки его подпредставлений. Такое представление, безусловно, проверено на попадание, но оно немедленно отвечает, что ни оно, ни какое-либо из его подпредставлений не являются представлением попадания.

В UIScrollView для userInteractinonEnabled установлено значение NO. Таким образом, когда VCViewContainersView проверяет свое подпредставление UIScrollView, и UIScrollView возвращает nil, поскольку его userInteractionEnabled имеет значение NO, VCViewContainersView использует pointInside: withEvent: on себя, обнаруживает, что касание находится внутри себя, и возвращает себя как представление попадания (и поиск заканчивается). Это объясняет результат, который вы получаете.

Причина, по которой этого не происходит, когда вы выполняете проверку нажатия с помощью слоев, состоит в том, что слои не доступны для касания и ничего не знают о правилах касаний, поэтому они игнорируют userInteractionEnabled, который является функцией просмотра, а не особенность слоя. Тестирование попаданий на уровне является своего рода клуджем, предназначенным только для случаев, когда представление содержит целую иерархию слоев (без иерархии представлений) и вы хотите смоделировать, что конкретный слой является сенсорным. Документы действительно говорят вам, что логика для hitTest слоя отличается от логики для hitTest представления: withEvent:, хотя они не в состоянии объяснить, как именно.

Я не знаю, почему вы установили, что ваш вид прокрутки не сенсорный, но если это важно для вас, вы можете переопределить hitTest: withEvent: в подклассе UIScrollView, чтобы он проверял свои подпредставления, но возвращал nil, если все из них возвращают ноль.

1 голос
/ 28 мая 2011

Возможно, вы захотите попробовать создать подкласс UIScrollView для получения касаний объектов внутри него.

По умолчанию ваши прикосновения будут приниматься вашим UIScrollView, поэтому, если вы хотите получать прикосновения к объектам внутри него, вам нужно настроить это явно.

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

Вот .h:

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface TouchScroller : UIScrollView 
{
}

@end

И .m:

#import "TouchScroller.h"


@implementation TouchScroller

- (id)initWithFrame:(CGRect)frame 
{
return [super initWithFrame:frame];
}

- (void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event 
{   
// If not dragging, send event to next responder
if (!self.dragging) 
    [self.nextResponder touchesEnded: touches withEvent:event]; 
else
    [super touchesEnded: touches withEvent: event];
}

@end

Это должно сделать это.

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

Если я правильно понимаю стек представлений, то ваша кнопка является подпредставлением некоторого UIImageView - для него userInteractionEnabled свойство установлено в NO (по умолчанию), поэтому представление изображения и все его подпредставления не получат никаких событий касания.

Установка свойства userInteractionEnabled представления изображения на YES должна решить проблему

...