#objective-c #core-animation #core-graphics
#objective-c #ядро-анимация #ядро-графика
Вопрос:
Я хочу замаскировать a CALayer
с CAShapeLayer
помощью, потому что изменения формы могут быть анимированы.
Когда я использую CAShapeLayer
как маску, закругленные углы растягиваются. Однако, если я возьму ту же форму, создам NSImage
с ее помощью изображение и использую его для маскировки CALayer
, закругленные углы будут в полном порядке.
Вот код, который я использую для маскировки слоев (вы также можете загрузить весь пример проекта):
CGColorRef backgroundColor = CGColorCreateGenericRGB(0.0, 0.0, 0.0, 1.0f);
[self.window.contentView setLayer:[CALayer layer]];
[self.window.contentView setWantsLayer:YES];
[[self.window.contentView layer] setFrame:[self.window.contentView frame]];
CALayer *imageBasedMaskLayer = [CALayer layer];
[imageBasedMaskLayer setContents:(id)[[self maskWithSize:NSMakeSize(50, 50)] CGImageForProposedRect:NULL context:nil hints:nil]];
[imageBasedMaskLayer setFrame:CGRectMake(0, 0, 50, 50)];
CALayer *layerWithImageBasedMaskLayer = [CALayer layer];
[layerWithImageBasedMaskLayer setBackgroundColor:backgroundColor];
[layerWithImageBasedMaskLayer setMask:imageBasedMaskLayer];
CAShapeLayer *shapeBasedMaskLayer = [CAShapeLayer layer];
CGPathRef maskShape = [self newMaskPathWithFrame:NSMakeRect(0, 0, 50, 50)];
[shapeBasedMaskLayer setPath:maskShape];
[shapeBasedMaskLayer setFillRule:kCAFillRuleEvenOdd];
CGPathRelease(maskShape);
[shapeBasedMaskLayer setFrame:CGRectMake(0, 0, 50, 50)];
CALayer *layerWithShapeBasedMaskLayer = [CALayer layer];
[layerWithShapeBasedMaskLayer setBackgroundColor:backgroundColor];
[layerWithShapeBasedMaskLayer setMask:nil];
[layerWithShapeBasedMaskLayer setMask:shapeBasedMaskLayer];
[layerWithImageBasedMaskLayer setFrame:CGRectMake(50, 50, 50, 50)];
[layerWithShapeBasedMaskLayer setFrame:CGRectMake(120, 50, 50, 50)];
[[self.window.contentView layer] addSublayer:layerWithImageBasedMaskLayer];
[[self.window.contentView layer] addSublayer:layerWithShapeBasedMaskLayer];
CGColorRelease(backgroundColor);
И два метода, которые я использую для создания NSImage
и CGPathRef
.
- (NSImage *)maskWithSize:(CGSize)size;
{
NSImage *maskImage = [[NSImage alloc] initWithSize:size];
[maskImage lockFocus];
[[NSColor blackColor] setFill];
CGPathRef mask = [self newMaskPathWithFrame:CGRectMake(0, 0, size.width, size.height)];
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
CGContextAddPath(context, mask);
CGContextFillPath(context);
CGPathRelease(mask);
[maskImage unlockFocus];
return [maskImage autorelease];
}
- (CGPathRef)newMaskPathWithFrame:(CGRect)frame;
{
CGFloat cornerRadius = 3;
CGFloat height = CGRectGetMaxY(frame);
CGFloat width = CGRectGetMaxX(frame);
CGMutablePathRef maskPath = CGPathCreateMutable();
CGPathMoveToPoint(maskPath, NULL, 0, height-cornerRadius);
CGPathAddArcToPoint(maskPath, NULL, 0, height, cornerRadius, height, cornerRadius);
CGPathAddLineToPoint(maskPath, NULL, width-cornerRadius, height);
CGPathAddArcToPoint(maskPath, NULL, width, height, width, height-cornerRadius, cornerRadius);
CGPathAddLineToPoint(maskPath, NULL, width, cornerRadius);
CGPathAddArcToPoint(maskPath, NULL, width, 0, width-cornerRadius, 0, cornerRadius);
CGPathAddLineToPoint(maskPath, NULL, cornerRadius, 0);
CGPathAddArcToPoint(maskPath, NULL, 0, 0, 0, cornerRadius, cornerRadius);
CGPathCloseSubpath(maskPath);
return maskPath;
}
Пожалуйста, обратите внимание, что фактическая маска, которую я хочу создать, сложнее, чем закругленный прямоугольник, иначе я бы использовал некоторые из более простых методов рисования. Я пробовал различные CGPath
функции рисования, проблема не исчезла.
Чего мне здесь не хватает?
Комментарии:
1. Это странно. Это звучит как системная ошибка. Я бы посоветовал зарегистрировать ошибку с помощью программы Apple bug reporter.
2. Это действительно странно. Еще один, потенциально интересный пункт данных: Если вместо маскировки слоем формы вы установите
cornerRadius
значение 3, это выглядит правильно. (т. Е. Не показывает растяжения) Я понимаю, что это не решает вашу проблему, но добавляет загадочности.
Ответ №1:
Это потому CAShapeLayer
, что скорость предпочтительнее точности. Вот почему иногда это может быть отключено.
Фигура будет нарисована сглаженной, и, когда это возможно, она будет отображена в пространстве экрана перед растрированием, чтобы сохранить независимость от разрешения. Однако некоторые виды операций обработки изображений, такие как фильтры основного изображения, применяемые к слою или его предшественникам, могут привести к растеризации в локальном координатном пространстве.
Примечание: Растеризация формы может отдавать предпочтение скорости, а не точности. Например, пиксели с несколькими пересекающимися сегментами пути могут не давать точных результатов.
Решение
Вы могли бы использовать
layerWithShapeBasedMaskLayer.cornerRadius = 3.0;
чтобы закруглить все ваши углы. Вам больше не нужно CAShapeLayer
. Вы даже можете продолжать использовать свой CAShapeLayer
в качестве подслоя для анимации пути. Просто установите
layerWithShapeBasedMaskLayer.masksToBounds = YES;