Во-первых, проверьте это очень удобное расширение 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 года: Первый ах-ха приобретенный момент! Проблема не в Simulator-vs-iPhone. Это Retina против Non-Retina! Те же симптомы возникают в симуляторе при использовании версии Retina. Возможно, решение сосредотачивается вокруг масштабирования (CTM?) Каким-то образом/формой/формой. Руководство по двумерному программированию Quartz также сообщает, что "приложения iOS должны использовать UIGraphicsBeginImageContextWithOptions." Я чувствую, что я очень близок к решению здесь!