Предоставление содержимого слоя Core Animation

Cocoa

При использовании Cocoa видов вы должны использовать подкласс NSView или UIView и реализовать drawRect: для того, чтобы показывать чего-либо. Однако в случае с CALayer, последний может быть использован напрямую, без использования подклассов. Потому что CALayer это совместимый класс контейнер для кодирования ключ-значение, то есть Вы можете хранить любые значения в любом случае, подклассов часто можно полностью избежать.

Предоставление содержимого CALayer

Вы определяете контент CALayer, к примеру, одним из следующих способов:

  • Явно задаете свойство contents слоя например, с использованием CGImageRef с содержимым изображения.
  • Укажите делегат, который предусматривает, или рисует, контент.
  • Создайте подкласс CALayer и переопределите один из методов display.

Установка свойства contents

Содержимое изображение слоя определяется contents свойством CGImageRef. Это может быть сделано из другого объекта, когда слой создается или в любое другое время.

Листинг 1 Установка свойства слоя contents

CALayer *theLayer;

// Создаем слой и устанавливаем границы и позицию
theLayer=[CALayer layer];
theLayer.position=CGPointMake(50.0f,50.0f);
theLayer.bounds=CGRectMake(0.0f,0.0f,100.0f,100.0f);

// Устанавливаем свойство contents в CGImageRef
// указанный theImage (загружено в другом месте)

theLayer.contents=theImage;

Использование делегатов для предоставления содержимого

Вы можете нарисовать содержимое вашего слоя, или лучше инкапсулировать установление содержимого изображения слоя путем создания делегата класса, который реализует один из следующих методов: displayLayer: или drawLayer:inContext:.

Реализация метода отрисовки контента делегата не приводит автоматически к отрисовке слоя с помощью этой реализации. Вместо этого вы должны явно указать слой например повторным кэшированием контента, либо отправить ему setNeedsDisplay или setNeedsDisplayInRect: сообщение, или установть его needsDisplayOnBoundsChange свойство в YES.

Делегаты, которые реализуют метод displayLayer: могут определить, какие изображения должны быть отображены в указанном слое, а затем установить contents свойство слоя соответственно. Например, в реализации displayLayer: в "системе координат слоя" устанавливает свойство contents theLayer в зависимости от значения ключа. Наследование не требуется для хранения состояния значения, потому что экземпляр CALayer действует как контейнер кодирования ключ-значение.

Листинг 2 Пример реализации метода делегата displayLayer:

- (void)displayLayer:(CALayer *)theLayer
{
    // Проверка значения state слоя с помощью ключа
    if ([[theLayer valueForKey:@"state"] boolValue])
    {
        // отображаем значение yes
        theLayer.contents=[someHelperObject loadStateYesImage];
    }
    else {
        // отображаем значение no
        theLayer.contents=[someHelperObject loadStateNoImage];
    }
}

Если вам необходимо нарисовать содержимое слоя, а не загружать его из образа, вы реализуете метод делегата drawLayer:inContext:. Делегату передается слой, для которого требуется контент и CGContextRef для отрисовки контента.

Например, в реализации drawLayer:inContext: в "Задание геометрии слоя" рисует путь используя ключевое значение lineWidth возвращаемое theLayer.

Листинг 3 Пример реализации метода делегата drawLayer:inContext:

- (void)drawLayer:(CALayer *)theLayer inContext:(CGContextRef)theContext
{
    CGMutablePathRef thePath = CGPathCreateMutable();

    CGPathMoveToPoint(thePath,NULL,15.0f,15.f);
    CGPathAddCurveToPoint(thePath, NULL, 15.f,250.0f, 295.0f,250.0f, 295.0f,15.0f);

    CGContextBeginPath(theContext);
    CGContextAddPath(theContext, thePath );

    CGContextSetLineWidth(theContext, [[theLayer valueForKey:@"lineWidth"] floatValue]);
    CGContextStrokePath(theContext);

    // освобождение the path
    CFRelease(thePath);
}

Предоставление CALayer содержимого с подклассами

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

Подкласс CALayer может переопределить метод display и настроить содержимое слоя на соответствующее изображение. Например, в "Преобразование геометрии слоя» предоставляет такую ​​же функциональность как реализация displayLayer: в делегате "Система координат слоя". Разница в том, что подкласс определяет state как свойство экземпляра, а не в зависимости от ключ-значение кодирования контейнера извлеченного из CALayer.

Листинг 4 Пример переопределения метода display CALayer

- (void)display
{
  // проверка свойства state слоя
  if (self.state)
  {
    // отображаем изображение yes
    self.contents=[someHelperObject loadStateYesImage];
  }
  else {
    // отображаем изображение no
    self.contents=[someHelperObject loadStateNoImage];
  }
}

Подкласс CALayer может отрисовывать контент слоя в графическом контексте, переопределив метод drawInContext:.

Листинг 5 Пример переопределения метода CALayer drawInContext:

- (void)drawInContext:(CGContextRef)theContext
{
    CGMutablePathRef thePath = CGPathCreateMutable();

    CGPathMoveToPoint(thePath,NULL,15.0f,15.f);
    CGPathAddCurveToPoint(thePath, NULL, 15.f,250.0f, 295.0f,250.0f, 295.0f,15.0f);

    CGContextBeginPath(theContext);
    CGContextAddPath(theContext, thePath );

    CGContextSetLineWidth(theContext, self.lineWidth);
    CGContextSetStrokeColorWithColor(theContext, self.lineColor);
    CGContextStrokePath(theContext);
    CFRelease(thePath);
}

Реализация подкласса и реализация одного из методов отрисовки контента не приводит автоматически к отрисовке слоя с помощью этой реализации. Вместо этого вы должны явно вызвать экземпляр повторным кэшированием контента, либо отправить ему setNeedsDisplay или setNeedsDisplayInRect: сообщение, или установть его needsDisplayOnBoundsChange свойство в YES.

Позиционирование содержимого внутри слоя

Свойство contentsGravity CALayer позволяет позиционировать и масштабировать изображение содержимого слоя в границах слоя. По умолчанию, содержимое изображение заполняет границы слоя полностью, игнорируя естественные пропорции изображения.

Используя константу позиционирования contentsGravity можно указать, что изображение помещают вдоль любого из краев слоя, в углах слоя, или по центру в границах слоя. Однако, при использовании константы позиционирования свойство contentsCenter не используется. В таблице 1 перечислены константы позиционирования и их соответствующие позиции.

Таблица 1 Константы размещения свойства слоя contentsGravity

Константа размещенияОписание
kCAGravityTopLeftРасполагает содержимое изображение в верхнем левом углу слоя.
kCAGravityTopПозиция изображения контента горизонтально по центру вдоль верхнего края слоя.
kCAGravityTopRightРасполагает содержимое изображение в правом верхнем углу слоя.
kCAGravityLeftРасполагает содержимое изображение по вертикали по центру левого края слоя.
kCAGravityCenterРасполагает содержимое изображения в центре слоя.
kCAGravityRightРасполагает содержимое изображения по вертикали по центру правого края слоя.
kCAGravityBottomLeftРасполагает содержимое изображение в нижнем левом углу слоя.
kCAGravityBottomРасполагает содержимое изображение по центру вдоль нижнего края слоя.
kCAGravityBottomRightРасполагает содержимое изображение в правом верхнем углу слоя.

"Система координат слоя" показывает поддерживаемые позиции контента и соответствующие константы.

Рисунок 1 константы позиции свойства contentsGravity слоя

layer contentsGravity

Изображение контента можно масштабировать вверх или вниз, установив одну из констант свойства contentsGravity(перечисленных в Таблице 2). Только тогда, когда с помощью одной из этих констант, свойство contentsCenter влияет на размер образа контента.

Таблица 2 Константы масштабирования слоя для свойства contentsGravity

Константа масштабированияОписание
kCAGravityResizeИзменение размера изображения контента, чтобы полностью заполнить границы слоя, потенциально игнорируя естественные аспекты контента. Это значение по умолчанию.
kCAGravityResizeAspectИзменение размера изображения контента в масштабе, так, что он отображается как можно больше в границах слоя, но все еще сохраняет свой естественный вид.
kCAGravityResizeAspectFillИзменение размера изображения контента в масштабе, так, что оно отображается заполненяя границы слоя, но сохранив естественный вид. Это может привести к продлению содержимого за границы слоя.

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

Рисунок 2 Константы масштабирования слоя для свойства contentsGravity

CALayer position mask
Примечание: Использование любых констант kCAGravityResize, kCAGravityResizeAspect и kCAGravityResizeAspectFill сделают константы contentsGravity размещения в таблице 1, не имеющими значения. Контент заполнит границы слоя, так что невозможно спозиционировать содержимое с помощью этих констант.
 
 
homeЗаметили ошибкукарта сайта 
   Made on a Mac