Свойства в подклассе CALayer не отслеживаются CATransaction - PullRequest
3 голосов
/ 20 января 2012

У меня есть подкласс CALayer с пользовательским свойством, объявленным так:

@interface MyLayer : CALayer
    @property (nonatomic,retain) NSNumber *customValue;
@end
@implementation MyLayer
    @synthesize customValue = _customValue;
@end

Я хочу анимировать это свойство внутри явного CATranasction, поэтому я настроил делегата с реализованным методом actionForLayer:forKey:, который возвращает анимацию, однако любые изменения в someMyLayerInstance.customValue внутри [CATransaction begin] ... [CATransaction end] не приводят в actionForLayer:forKey вызове с соответствующим значением ключа.

Тем не менее, обнуление свойства в MyLayer и внесение изменений в myLayerInstance путем вызова setValue:forKey: приводит к , в результате чего actionForLayer:forKey: будет вызван.

Похоже, что это потому, что CALayer делает некоторые mojo для кодирования ключа / значения для неопределенных свойств. Как я могу воссоздать это mojo, чтобы я мог объявить свойства в MyLayer, но делегат анимации все равно должен их наблюдать?

1 Ответ

7 голосов
/ 30 января 2012

Самое важное, что вам нужно реализовать все CALayer средства доступа, использующие @dynamic.Не используйте @synthesize и не используйте средства доступа напрямую.CALayer генерирует все свои собственные обработчики свойств (как вы косвенно обнаружили), и вам нужно разрешить их использовать.

Вам также нужно сообщить CALayer, что это свойство влияет на отображение (что вы, возможно, уже сделали, учитывая ваши другие комментарии).Если нет, вы делаете это путем реализации +needsDisplayForKey: и возврата YES для вашего ключа.

Вот пример CALayer, который анимирует пользовательское свойство (взято из главы 7 в Программирование на iOS 5, «Нажимая пределы» . Доступен полный пример кода на сайте Wiley.) Этот пример реализует actionForKey: в слое, но вы все равно можете реализовать эту часть в делегате, если хотите.

@implementation CircleLayer
@dynamic radius;

...

+ (BOOL)needsDisplayForKey:(NSString *)key {
  if ([key isEqualToString:@"radius"]) {
    return YES;
  }
  return [super needsDisplayForKey:key];
}

- (id < CAAction >)actionForKey:(NSString *)key {
  if ([self presentationLayer] != nil) {
    if ([key isEqualToString:@"radius"]) {
      CABasicAnimation *anim = [CABasicAnimation
                                animationWithKeyPath:@"radius"];
      anim.fromValue = [[self presentationLayer] 
                        valueForKey:@"radius"];
      return anim;
    }
  }

  return [super actionForKey:key];
}

@end
...