Во-первых, посмотрите это очень удобное расширение для CALayer из других мест на SO. Это помогает определить, является ли точка в назначенном содержимом слоя CGImageRef прозрачной или нет.
n.b .: Нет никакой гарантии, что contents
слоя будет представлен или отвечает, как если бы это был CGImageRef . (Это может иметь значение для более широкого использования расширения, на которое есть ссылка, как указано выше.) В моем случае, однако, я знаю, что слои, которые я тестирую, имеют contents
, которым был присвоен CGImageRef . (Надеюсь, это не изменится из-под меня после назначения! Плюс я замечаю, что contents
сохраняется.)
Хорошо, вернемся к проблеме. Вот как я использую расширение. Для начала я изменил селектор с containsPoint:
на containsNonTransparentPoint:
(мне нужно сохранить оригинальный метод.)
Теперь у меня есть подкласс UIImageView , который использует семь CALayer объектов. Они используются для анимации на основе непрозрачности (пульсирующие / светящиеся эффекты и состояния включения / выключения). Каждый из этих семи слоев имеет известный CGImageRef в его contents
, который эффективно «покрывает» (воздушные кавычки) одну часть всего представления своим собственным диапазоном цветов. Остальная часть каждого изображения в соответствующем слое является прозрачной.
В подклассе я регистрируюсь на жесты одним нажатием. Когда кто-то прибывает, я прохожу свои слои, чтобы увидеть, какой из них был эффективно повернут (то есть, у какого есть непрозрачная точка, где я постучал, сначала найден выигрыш), а затем я могу делать все, что нужно.
Вот как я справляюсь с жестом:
- (IBAction)handleSingleTap:(UIGestureRecognizer *)sender {
CGPoint tapPoint = [sender locationInView:sender.view];
// Flip y so 0,0 is at lower left. (Required by layer method below.)
tapPoint.y = sender.view.bounds.size.height - tapPoint.y;
// Figure out which layer was effectively tapped. First match wins.
for (CALayer *layer in myLayers) {
if ([layer containsNonTransparentPoint:tapPoint]) {
NSLog(@"%@ tapped at (%.0f, %.0f)", layer.name, tapPoint.x, tapPoint.y);
// We got our layer! Do something useful with it.
return;
}
}
}
Хорошие новости? Все это прекрасно работает на iPhone Simulator с iOS 4.3.2. (FWIW, я на Lion, работающем Xcode 4.1.)
Однако на моем iPhone 4 (с iOS 4.3.3) он даже близко не подходит! Ни один из моих сигналов не совпадает с любыми слоями, которые я ожидаю от них.
Даже если я попытаюсь предложить использовать CGContextSetBlendMode при рисовании в контексте пикселя 1x1, кубик не будет.
Я надеюсь, что это ошибка пилота, но мне еще предстоит выяснить, в чем заключается несоответствие. Метчики имеют рисунок, но не различимы.
Возможно, существует проблема с границами данных. Возможно, я должен сделать что-то другое, чем перевернуть координату Y в левом нижнем углу изображения. Просто пока не уверен.
Если кто-нибудь может пролить свет на то, что может быть не так, я был бы очень признателен!
ОБНОВЛЕНИЕ, 22 сентября 2011 г .: Первый момент ах-ха! Проблема не в симуляторе против iPhone.
Это Retina против Non-Retina! Те же симптомы возникают в симуляторе
при использовании версии Retina. Возможно решение сосредоточено вокруг масштабирования (CTM?) В некотором роде / форме / форме. Руководство по программированию Quartz 2D также рекомендует, чтобы «приложения для iOS использовали UIGraphicsBeginImageContextWithOptions ». Я чувствую, что я очень близок к решению здесь!