проверка попадания слоя выполняется только при возврате слоя при касании нижней половины слоя

StackOverflow https://stackoverflow.com/questions/401040

Вопрос

У меня есть подуровень в представлении с поддержкой слоев.Содержимое подслоя имеет значение Image Ref и представляет собой прямоугольник размером 25x25.
Я выполняю тест попадания на суперслое при вызове методов touchesBegan и touchesMoved.Метод проверки попадания, по сути, возвращает подслой, если к нему прикоснуться, НО только если прикоснуться к нижней половине изображения.Если коснуться верхней половины изображения, то вместо этого будет возвращен суперслой.

Я точно знаю, что iPhone OS компенсирует тенденцию к тому, что количество прикосновений пользователя ниже, чем предполагалось.Даже если я изменю размер подслоя до большего размера, 50x50, он будет вести себя так же.

Есть какие-нибудь мысли?

Это было полезно?

Решение 6

Спасибо, Кевин...

В итоге я просто переделал свой код с помощью UIViews.Было слишком сложно просто попытаться выяснить, почему UIView не знал, к какому слою прикасались.Вся моя аргументация в пользу этой идеи заключалась в том, что у меня будет более 100 элементов на экране одновременно, и я подумал, что слои будут проще для процессора, чем UIViews.Сейчас у меня запущено приложение, и 100 просмотров не дают ему никаких сбоев.

Мое предложение другим - просто придерживайтесь UIViews для тестирования хитов, когда это возможно, это значительно упрощает код

Другие советы

В документации для hitTest говорится:

/* Returns the farthest descendant of the layer containing point 'p'.
 * Siblings are searched in top-to-bottom order. 'p' is in the
 * coordinate system of the receiver's superlayer. */

Итак, вам нужно сделать (что-то вроде этого):

CGPoint thePoint = [touch locationInView:self];
thePoint = [self.layer convertPoint:thePoint toLayer:self.layer.superlayer];
CALayer *theLayer = [self.layer hitTest:thePoint];

(Повторяю ответ из другого поста для полноты картины)

Похоже, что слой получает штрихи не только к нижним пикселям.Вместо этого кажется, что "фактический" экранный слой и содержимое слоя определяются разными CGRects.Изображение отображается в ожидаемых координатах, в то время как слой, реагирующий на прикосновения, смещен ниже изображения.Под "ниже" я подразумеваю, что начало изображения находится в (200, 200), а начало слоя, который реагирует на прикосновения, находится в (200, 220).

Ниже я публикую некоторый тестовый код, который я использовал для воссоздания проблемы.Сначала мой подкласс view, а затем мой контроллер view.Мы высоко ценим любые рассуждения, стоящие за этой проблемой.

Подкласс My View:

#import "myView.h"
#import <QuartzCore/QuartzCore.h>


@implementation myView


- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    CGPoint currentLocation = [[touches anyObject] locationInView:self];

    CALayer *currentLayer = [self.layer hitTest:currentLocation];

    CGPoint center = [currentLayer position];

    NSLog([currentLayer valueForKey:@"isRootLayer"]);

    if(![currentLayer valueForKey:@"isRootLayer"]) {

        if (center.x != 200) {

            [currentLayer setPosition:CGPointMake(200.0f, 200.0f)];     

        } else {
            [currentLayer setPosition:CGPointMake(100.0f, 100.0f)];     

        }
    }
}


- (id)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        // Initialization code
    }
    return self;
}


- (void)drawRect:(CGRect)rect {
    // Drawing code
}


- (void)dealloc {
    [super dealloc];
}


@end

Мой Контроллер просмотра:

#import "layerTestViewController.h"
#import <QuartzCore/QuartzCore.h>


#define ELEMENT_PERIOD_SIZE 50
#define ELEMENT_GROUP_SIZE 50

@implementation layerTestViewController





// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];

    CALayer  *myLayer = [CALayer layer];
    CGRect layerFrame =CGRectMake(0.0f, 0.0f, ELEMENT_GROUP_SIZE, ELEMENT_PERIOD_SIZE);
    myLayer.frame = layerFrame; 

    [myLayer setName:[NSString stringWithString:@"test"]];
    [myLayer setValue:[NSString stringWithString:@"testkey"] forKey:@"key"];

    UIGraphicsBeginImageContext(layerFrame.size);
    [[UIColor blueColor] set];
    UIRectFill(layerFrame);
    UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    myLayer.contents = (id)[theImage CGImage];
    myLayer.position = CGPointMake(100.0f, 100.0f);

    [self.view.layer addSublayer:myLayer];   

    [self.view.layer setValue:[NSString stringWithString:@"YES"] forKey:@"isRootLayer"];
    NSLog([self.view.layer valueForKey:@"isRootLayer"]);

}




- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
    // Release anything that's not essential, such as cached data
}


- (void)dealloc {
    [super dealloc];
}

@end

Принятый ответ не решает проблему, но ответ schwa решает.

У меня есть окно, контроллер представления и view.Вид принимает касания и вызовы hitTest: на своем слое.У меня была такая же проблема, и я обнаружил, что точка зрения верна, но в hitTest: координата y точки отклонена на 20 пикселей, что соответствует высоте строки состояния.

Путем сопоставления точки с системой координат суперслоя, как предложил schwa, эта проблема устранена."Таинственный" суперслой - это корневой уровень супервизора.В моем случае это оконный слой (frame (0, 0, 320, 480)).

Если касания распознаются только в нижней части, одна из возможностей заключается в том, что другое подвидение покрывает верхнюю половину этого подвида.У вас есть несколько подвидов или только одно изображение?Если у вас есть несколько вложенных представлений и у любого из них цвет фона такой же, как clearColor, попробуйте присвоить ему сплошной цвет фона для тестирования.Таким образом, вы будете знать, закрывается ли ваш подраздел другим подразделом или нет.

Надеюсь, это поможет.

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

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

Это трудно объяснить, но если вы запустите код, все станет ясно.

Спасибо

Когда я пробую ваш код, я получаю почти корректное поведение, за исключением того, что касания часто не распознаются на самом краю подслоя.Я немного сбит с толку относительно того, что происходит.Возможно, вы захотите попробовать сделать что-то вроде того, что при регистрации касания добавьте новый крошечный слой в том месте, где произошло касание (например, квадрат размером 5x5 какого-либо цвета), а затем снова удалите его через 3 секунды.Таким образом, вы можете отследить, где, по мнению CA, произошло касание, а где на самом деле находится ваш курсор.

Кстати, вам не нужно создавать CGImage для вашего синего содержимого, вы можете просто установить размер слоя backgroundColor Для [UIColor blueColor].CGColor.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top