Лучший шаблон для обработки касаний в анимированном UIView/CALayer?

У меня есть экземпляр UIView, который я анимирую с помощью CAKeyframeAnimation. Это зацикленная анимация, которая будет постоянно находиться в движении. Однако мне нужно разрешить взаимодействие пользователя с элементом (точнее, реагировать на касания). Поскольку CoreAnimation перемещает только уровень представления, а не модель, я не могу использовать экземпляр UIButton, например, для получения событий touchUpInside.

Рассмотрим следующий базовый пример макета:

введите здесь описание изображения

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

Все это кажется довольно хакерским, чтобы просто прикоснуться к анимированному UIView. Каковы лучшие шаблоны для обработки касаний для анимированных экземпляров UIView/CALayer?


person Wayne Hartman    schedule 16.02.2012    source источник
comment
Обязательно ли использовать ЦА? CA лучше всего подходит для плавной анимации, потому что он легкий, и он легкий, потому что в нем нет всего материала для обработки событий (отчасти правда). Если бы вы каким-то образом добавили к нему обработку событий, вы могли бы разрушить плавные возможности GPU. Я не уверен, что есть способ обойти это. Насколько гладкой она должна быть? Возможно, вы захотите анимировать с помощью некоторых других методов анимации, которые фактически перемещают модель с помощью ЦП. Просто мысли вслух вместе с тобой.   -  person Vinnie    schedule 16.02.2012
comment
@Vinnie Винни - проблема в том, что этот пример - очень простая анимация. Настоящая проблема на самом деле включает в себя несколько ключевых кадров для анимации вида вдоль пути, а также для некоторого вращения при его перемещении по пути. Анимация также должна повторяться до бесконечности, поэтому использование блоков UIView действительно не кажется подходящим вариантом.   -  person Wayne Hartman    schedule 16.02.2012


Ответы (2)


Я считаю, что отслеживание касания в супервизоре правильное. Но я бы провел тестирование ударов в супервизоре, а не отправил уведомление контроллеру представления. Что-то вроде этого:

Создайте класс MYAnimationContainerView (синяя рамка).

Дайте ему обратный вызов делегата или блока, который устанавливает владеющий контроллер представления. Например:

__weak id weakSelf = self;
MYAnimationContainerView *view = [[MYAnimationContainerView alloc] initWithTouchCallback:^(UIView *touchedView){
  [weakSelf handleTouchToView:touchedView];
}];

В MYAnimationContainerView переопределите как touchesBegan:withEvent:, так и touchesEnded:withEvent:. В began выполните проверку нажатия на уровне представления движущихся представлений. Следите за тем, какой из них (если есть) был затронут. В ended выполните еще один тест на попадание. Если это тот же вид, то вызовите свой обратный вызов.

Вышеупомянутое можно было бы так же легко реализовать с помощью протокола delegate, а не блока. У меня просто появилась привычка предпочитать блоки протоколам делегатов с одним методом.

Вы также можете реализовать его с помощью target/selector, но этот шаблон должен быть несколько хлопот с ARC, и сегодня я не одобряю его использование.

person Rob Napier    schedule 16.02.2012
comment
Ваш подход мне нравится гораздо больше. Спасибо! - person Wayne Hartman; 17.02.2012

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

В случае многих таких объектов события касания обрабатываются сами по себе.

Я не уверен, что это то, что вы ожидали.

person Vignesh    schedule 16.02.2012
comment
Прикосновения не обрабатываются сами по себе, потому что анимируется только слой представления, а не слой модели, где обрабатываются касания. - person Wayne Hartman; 16.02.2012