Как именно подклассировать CALayer и использовать настраиваемое свойство?

Я пытаюсь создать подкласс CALayer с пользовательским свойством index, который можно как анимировать, так и напрямую изменить, чтобы отобразить другое изображение на основе индекса.

В заголовке я заявил:

@property NSUInteger index;

В реализации я перегрузил needDisplayForKey:

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

Теперь, в методе display, я хочу отобразить изображение на основе индекса. Однако во время анимации значение self.index никогда не изменяется, поэтому я должен запрашивать значение уровня представления, в отличие от примера Предоставление содержимого CALayer по подклассу:

- (void)display
{
    NSUInteger presentationIndex = [(CustomLayer *)[self presentationLayer] index];
    self.contents = (id)[[images objectAtIndex:presentationIndex] CGImage];
}

Проблема в том, что если я это сделаю, я не могу установить значение index непосредственно вне анимации, потому что он изменит только слой модели, а метод display явно запросит уровень представления.

Если я добавлю метод инициализации, который копирует значение index, он работает:

- (id)initWithLayer:(id)layer
{
    self = [super initWithLayer:layer];
    if (self) {
        if ([layer isKindOfClass:[CustomLayer class]])
            self.index = [(CustomLayer *)layer index];
    }
    return self;
}

Однако после или до анимации всегда есть 1 сбой изображения, потому что представление или значение модели не совпадают (в зависимости от того, установлен ли значение index на целевое значение или нет).

  • Удивительно, но похоже, что метод drawInContext: всегда имеет правильное значение для [self index], но это не тот метод, который я хочу использовать, поскольку я просто установил свойство content с изображением.
  • Я получаю различное поведение в зависимости от того, как я реализую свойство index. Если я использую @dynamic index (который работает, хотя в документации не говорится, что пользовательские свойства getters/seters будут динамически реализованы), display вызывается каждый раз, когда изменяется значение index. Если я использую @synthesize или реализую сеттер, display не вызывается, поэтому мне также нужно будет изменить content в настройщике.
  • Должен ли я использовать переменную экземпляра? Должен ли я использовать динамическую реализацию? Или я должен использовать setValue:forKey: вместо этого?

Как вы можете видеть, я немного смущен тем, как получить результат, который я хочу, и как правильно реализовать подкласс CALayer с настраиваемым свойством. Любая помощь и объяснения будут оценены!

Ответы

Ответ 1

В Интернете есть отличный учебник, в котором объясняется, как создать пользовательский подкласс CALayer с анимированными свойствами. У меня еще не было возможности попробовать его, но я добавил его в закладки. Вот ссылка:

Анимация кусочков пирога с использованием пользовательского CALayer

Похоже, основные трюки:

Используйте @dynamic, а не @synthesize для анимационных свойств вашего пользовательского CALayer.

Переопределить actionForKey:, initWithLayer:, and needsDisplayForKey:, и возможно drawInContext: