Отслеживание анимации основной анимации

У меня есть два круга, которые перемещаются по экрану. Круги - это UIViews, которые содержат другие UIViews. Область вне каждого круга прозрачна.

Я написал функцию для создания CGPath, которая соединяет два круга с четырехсторонней формой. Я заполняю этот путь в прозрачном CALayer, который охватывает весь экран. Поскольку слой находится за двумя круговыми UIViews, он, кажется, соединяет их.

Наконец, два UIView анимируются с использованием Core Animation. позиция и размер обоих кругов изменяются во время этой анимации.

До сих пор единственным способом, с которым я имел успех, является прерывание анимации через регулярные интервалы с использованием NSTimer, а затем пересчитать и нарисовать луч в зависимости от местоположения класса presentationLayer. Однако четырехугольник отстает от кругов, когда анимация ускоряется.

Есть ли лучший способ сделать это с помощью Core Animation? Или мне следует избегать Core Animation и реализовать собственную анимацию с помощью NSTimer?

Ответ 1

У меня возникла аналогичная проблема. Я использовал слои вместо представлений для анимации. Вы можете попробовать что-то вроде этого.

  • Нарисуйте каждый элемент как CALayer и включите их в качестве подслоев для вашего слоя UIVIew контейнера. UIViews легче оживить, но у вас будет меньше контроля. Обратите внимание, что для любого вида вы можете получить слой с [view layer];
  • Создайте собственный подуровень для вашего четырехугольника. Этот слой должен иметь свойство или несколько свойств, которые вы хотите оживить для этого слоя. Позвольте называть это свойство "customprop". Поскольку это настраиваемый уровень, вы хотите перерисовать каждый кадр анимации. Для свойств, которые вы планируете оживить, ваш пользовательский класс класса должен вернуть YES needsDisplayForKey:. Таким образом вы гарантируете, что - (void) drawInContext: (CGContextRef) theContext вызывается в каждом кадре.
  • Поместите все анимации (круги и квад) в ту же транзакцию;

Для кругов вы, вероятно, можете использовать CALayers и установить контент, если это изображение, стандартным способом:

layer.contents = [UIImage imageNamed:@"circle_image.png"].CGImage;

Теперь, для четырехмерного слоя, подкласса CALayer и реализуем этот способ:

- (void)drawInContext:(CGContextRef)theContext{
  //Custom draw code here
}   
+ (BOOL)needsDisplayForKey:(NSString *)key{
   if ([key isEqualToString:@"customprop"])
      return YES;
    return [super needsDisplayForKey:key];
}   

Сделка будет выглядеть так:

[CATransaction begin];
CABasicAnimation *theAnimation=[CABasicAnimation animationWithKeyPath:@"customprop"];

theAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(1000, 1000)];
theAnimation.duration=1.0;
theAnimation.repeatCount=4;
theAnimation.autoreverses=YES;
theAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
theAnimation.delegate = self;
[lay addAnimation:theAnimation forKey:@"selecting"];

[CATransaction setValue:[NSNumber numberWithFloat:10.0f]
                     forKey:kCATransactionAnimationDuration];
circ1.position=CGPointMake(1000, 1000);
circ2.position=CGPointMake(1000, 1000);
[CATransaction commit];

Теперь все розыгрыши будут выполняться одновременно. Убедитесь, что drawInContext: реализация выполняется быстро. В противном случае анимация будет отставать.

После добавления каждого подуровня к слою UIViews rememeber для вызова [layer setNeedsDisplay]. Он не вызывается автоматически.

Я знаю, что это немного сложно. Однако полученные анимации лучше, чем использование NSTimer и перерисовка для каждого вызова.

Ответ 2

Если вам нужно найти текущее видимое состояние слоев, вы можете вызвать -presentationLayer на CALayer, о котором идет речь, и это даст вам слой, который приблизительно соответствует тому, который используется для рендеринга. Заметьте, я сказал, что приблизительные - это не гарантируется полностью точно. Однако это может быть достаточно хорошим для ваших целей.