如何子类化CALayer以用作另一个CALayer的遮罩?

5
我正在尝试为另一个图层创建一个蒙版,因此要子类化CALayer

我想使用我的CALayer子类来替换CAGradientLayer并将其用作渐变蒙版,如此处所述。

但是,我希望使用自定义的CALayer,该图层使用内部的CGGradient进行绘制,因为这应该比CAGradientLayer产生更平滑的结果(请参见此处)。我不关心性能,我需要更好的渐变质量。

我正在遵循此示例来创建我的CGGradient并将其存储在CALayer上。然而,我无法绘制出蒙版。

我不知道在哪里放置绘图代码:CALayerdisplaydrawInContext:(CGContextRef)ctxdrawInContext:(CGContextRef)ctx似乎在用作蒙版时没有被调用。

请容忍我,因为我对CoreAnimation还不熟悉。那么,如何修复这个问题,使我的CALayer子类可以作为CAGradientLayer的替代品,但使用CGGradient进行绘制?


我的当前代码在此处:

@interface CANiceGradientLayer : CALayer

@property (nonatomic) CGGradientRef gradient;
@property (atomic) CGPoint startPoint;
@property (atomic) CGPoint endPoint;

@end

@implementation CANiceGradientLayer

- (instancetype)initWithGradientRef:(CGGradientRef)gradient startPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint
{
    if ( !(self = [super init]) )
    {
        return nil;
    }

    self.gradient = CGGradientRetain(gradient);
    self.startPoint = startPoint;
    self.endPoint = endPoint;

    return self;
}

- (void)dealloc
{
    CGGradientRelease(self.gradient);
}

- (void)display
{
    NSLog(@"display");
}

- (void)drawInContext:(CGContextRef)ctx
{
    NSLog(@"drawInContext:");
    CGContextDrawLinearGradient(ctx, self.gradient, self.startPoint, self.endPoint, kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);;
}

- (void)renderInContext:(CGContextRef)ctx
{
    NSLog(@"renderInContext:");
}

@end

以下是我创建它的步骤:

size_t num_locations = 2;
CGFloat locations[2] = { 0.0, 1.0 };
CGFloat components[8] = { 1.0, 1.0, 1.0, 1.0,  // Start color
                          1.0, 1.0, 1.0, 0.0 }; // End color

CGColorSpaceRef rgbColorspace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(rgbColorspace, components, locations, num_locations);


self.collectionViewTickerMaskLayer = [[CANiceGradientLayer alloc] initWithGradientRef:gradient startPoint:CGPointZero endPoint:CGPointZero];


self.collectionViewTickerMaskLayer.anchorPoint = CGPointZero;
view.layer.mask = self.collectionViewTickerMaskLayer;

如果我使用一个CAGradientLayer,它可以正常工作(但是渐变看起来不好)。

只是猜测:继承自CAShapeLayer而不是CALayer? - 我认为您必须使用CAShapeLayers来设置mask属性(即使它接受任何CALayer对象)... - CodingMeSwiftly
@Cabus,楼主说使用CAGradientLayer也可以,所以我认为这不是问题所在。 - David Rönnqvist
我看到你正在覆盖 renderInContext: 方法。这可能是问题所在吗?请尝试调用 super 实现或将其注释掉,看看是否有变化。 - Léo Natan
1个回答

2
在将您的图层子类设置为蒙版之前,请在其上调用-setNeedsDisplay,这样您只需要重写CALayer子类的-drawInContext:。 这将帮助您调用该方法(CALayer使用其-display的默认实现来调用-drawInContext:,该方法在-setNeedsDisplay之后调用)。 您还可能需要设置图层的框架:
self.collectionViewTickerMaskLayer.frame = view.layer.bounds;
self.collectionViewTickerMaskLayer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;

这段代码存在逻辑问题。您正在使用一个端点 CGPointZero,因此即使调用了方法,也不会绘制任何渐变以遮盖您的图层。


就是这样,我漏掉了 “-setNeedsDisplay”。添加了它之后,“drawInContext:” 就像个老板一样被调用了。 - Ricardo Sanchez-Saez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接