Синхронизация изменений CADisplayLink в прогресс CAAnimation

Я пытаюсь объединить CADisplayLink и CAAnimation, чтобы я мог анимировать некоторые слои с помощью CAAnimation и настраивать другие в реальном времени на основе изменяющегося уровня представления анимированных слоев. Я понимаю, что CAAnimations выходят за пределы моего процесса, в то время как обратный вызов CADisplayLink в моем процессе, поэтому синхронизация никогда не будет полностью плотной. Тем не менее, я надеялся, что это будет лучше, чем то, что я вижу (я вижу, возможно, до 4-х кадров).

Свернувшись до простого фрагмента кода, я создаю кучу пар слоев. Половина из них – очертания, другая половина сплошных квадратов – все предметы имеют одинаковый размер. Цель состоит в том, чтобы анимировать эти пары прямоугольников, чтобы их контуры и квадраты всегда были вместе (т. Е. Один и тот же кадр).

В каждом цикле я установил новое положение для сплошного слоя и позвонил обратный вызов CADisplayLink, установив контурный слой на основе положения слоя представления его дополнительного сплошного слоя. На симуляторе это, похоже, работает большую часть времени, по крайней мере, для небольшого количества слоев. Как только я встаю до 24 пар слоев, некоторые контуры начинают отставать. На устройстве (iPad Air и iPhone 6) контур отстает даже на одном квадрате. Я делаю все тесты w / iOs 8.

Ниже приведена моя реализация ViewController.

@implementation ViewController { CADisplayLink *_displayLink; NSUInteger _startingLayerIndex; } #define NUMLAYERS 1 - (void)viewDidLoad { [super viewDidLoad]; _startingLayerIndex = self.view.layer.sublayers.count; for (int i=0; i<NUMLAYERS; ++i) { CALayer *outlineLayer = [[CALayer alloc] init]; outlineLayer.borderColor = [[UIColor blackColor] CGColor]; outlineLayer.borderWidth = 1.0; CALayer *fillLayer = [[CALayer alloc] init]; fillLayer.backgroundColor = [[UIColor redColor] CGColor]; { CGRect r = CGRectMake(self.view.center.x, self.view.center.y, 0, 0); r = CGRectInset(r, -22, -22); outlineLayer.frame = r; fillLayer.frame = r; } [self.view.layer addSublayer:fillLayer]; [self.view.layer addSublayer:outlineLayer]; } UITapGestureRecognizer *gr = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTap:)]; [self.view addGestureRecognizer:gr]; // WARNING - will create an ARC cycle. I don't care though, throwaway code _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(refreshDisplay:)]; [_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; [_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; [_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:UITrackingRunLoopMode]; _displayLink.paused = true; } -(void) refreshDisplay:(CADisplayLink *) displayLink { [CATransaction begin]; [CATransaction setDisableActions:true]; bool keepGoing = false; for (int i=0; i<NUMLAYERS; ++i) { CALayer *animatedLayer = [self.view.layer.sublayers objectAtIndex:(2*i)+_startingLayerIndex]; if (animatedLayer.animationKeys.count) { keepGoing = true; } CALayer *trackingLayer = [self.view.layer.sublayers objectAtIndex:(2*i)+_startingLayerIndex+1]; trackingLayer.position = [animatedLayer.presentationLayer position]; } _displayLink.paused = !keepGoing; [CATransaction commit]; } CGFloat randInRange(CGFloat r) { return (rand()%((int)r*2))/2.0; } -(void) onTap:(UITapGestureRecognizer *) gr { _displayLink.paused = false; [CATransaction begin]; [CATransaction setAnimationDuration:2.0]; //[CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]]; for (int i=0; i<NUMLAYERS; ++i) { CGSize sz = self.view.frame.size; CGPoint p = CGPointMake(randInRange(sz.width), randInRange(sz.height)); [[self.view.layer.sublayers objectAtIndex:(2*i)+_startingLayerIndex] setPosition:p]; } [CATransaction commit]; } @end 

Я пробовал 3 различные функции синхронизации, и я вижу те же результаты. Я также проверил частоту кадров с инструментами, и я получаю 58-60 кадров в секунду и все еще вижу видимое разделение.

Мне интересно, знает ли кто-нибудь лучший способ сделать это. Я знаю, что я мог бы преобразовать все анимации, которые будут управляться либо CAAnimation, либо CADisplayLink. Однако в моем случае ни одна из них не привлекательна. У меня есть сотни слоев на экране, все они взаимосвязаны (составляют всегда отзывчивое и полностью анимированное представление) – иногда иерархически. Core Animation делает жизнь намного более управляемой (и я считаю, что она более эффективна, хотя может быть, что «эффективность» является основной причиной моего отставания), поэтому я не хочу ее выкидывать. Меня не волнует необходимость параметризировать все мои анимации. Существует ряд слоев, которые зависят от кадров многих других слоев. Имея возможность запускать анимацию для большей части работы, просто делать некоторые угловые случаи «вручную» в режиме реального времени очень привлекательно с точки зрения дизайна (особенно в отношении обслуживания).

Кроме того, я понимаю, что UIKit Dynamics построена, чтобы обеспечить хорошую основу для анимированного и отзывчивого представления. Тем не менее, я корректирую размеры слоев, а положение слоев на экране потребует ограничения и привязки. Масштабирование до сотен, даже тысяч слоев кажется проблематичным, особенно когда процессор уже ограничен.

  • Маска UIView с вырезанным кругом
  • animateWithDuration: delay: options: animations: завершение: блокировка пользовательского интерфейса при использовании с UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse
  • CABasicAnimation сбрасывается при прокрутке края с помощью UINavigationController
  • Используйте анимацию UIView для реализации kCATransitionPush из CATransition
  • Возможны основные анимации с AVAssetWriter?
  • Как оживить NSLayoutConstraint в CAAnimationGroup
  • CALayers никогда не называет его drawLayer делегата: inContext: даже после и
  • UIView Subview для анимации
  • Явная анимация Core Animation не срабатывает для недавно добавленного подуровня
  • Есть ли способ предотвратить перекрытие теней CALayer от соседних слоев?
  • Иерархия CALayer, Лучший способ привлечь ее к контексту точно так, как показано на экране
  • Interesting Posts

    Нарисуйте внутри iOS Today Extension без прокрутки всего NC

    Права на Facebook, необходимые для того, чтобы пометить друга в стене.

    Общие полномочия iOS: проверьте, выбрал ли пользователь «Не сохранять пароли» в Safari

    iOS 11 – Невозможно изменить высоту панели навигации

    Имеет ли setNeedsDisplay немедленный эффект или просто поставлен в очередь на потом?

    Преобразование NSDictionary в NSArray

    Разработка iOS – uitableview с бесконечными уровнями

    UICollectionView cellForItemAtIndexPath возвращает nil после прокрутки

    iOS 8.2 не обращение к diddiscoverservices

    Компиляция Qt для iOS (маяк UIKit), часть 2

    Как добавить перечисления в модель области? RLMObject?

    Могу ли я запустить сеанс подключения многоуровневой связи в фоновом режиме?

    FIRInstanceID / WARNING STOP !! Сбросит идентификатор устройства из памяти

    При использовании UINavigationController методы viewWillAppear или viewDidAppear моего контроллера не вызываются

    Программный вход на веб-сайт с сохраненным именем пользователя и паролем

    Давайте будем гением компьютера.