如何将 CALayer 子类化为另一个 CALayer 掩码?
Posted
技术标签:
【中文标题】如何将 CALayer 子类化为另一个 CALayer 掩码?【英文标题】:How to subclass CALayer for use as another CALayer mask? 【发布时间】:2014-07-13 15:33:23 【问题描述】:我正在尝试继承 CALayer
以用作另一层的蒙版。
我想使用我的CALayer
子类代替CAGradientLayer
,并将其用于渐变蒙版,如here 所述。
但是,我希望使用自定义CALayer
来代替使用内部CGGradient
进行绘图,因为这应该会产生比CAGradientLayer
(see here) 更平滑的结果。我不关心性能,我想要更好的渐变质量。
我正在关注 this example 创建我的 CGGradient
并将其存储在 CALayer
.. 但是,我无法绘制蒙版。
我不知道把draw code放在哪里:CALayer
的display
也不是drawInContext:(CGContextRef)ctx
也不是drawInContext:(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 对象的事件)... @Cabus OP 说使用 CAGradientLayer 也可以,所以我认为这不是问题。 我看到你正在覆盖renderInContext:
。这可能是问题吗?请尝试调用超级实现或将其注释掉,看看是否有变化。
【参考方案1】:
在您的图层子类上调用-setNeedsDisplay
,然后再将其设置为遮罩,您只需覆盖CALayer
子类的-drawInContext:
。这将帮助您获得要调用的方法(CALayer 调用-drawInContext:
使用其默认实现-display
,在-setNeedsDisplay
之后调用)。您可能还需要设置图层的框架:
self.collectionViewTickerMaskLayer.frame = view.layer.bounds;
self.collectionViewTickerMaskLayer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
此代码存在逻辑问题。您使用的是 CGPointZero 端点,因此即使调用了这些方法,也不会绘制渐变来遮盖您的图层。
【讨论】:
就是这样,我错过了-setNeedsDisplay
。添加后drawInContext:
被称为老板。以上是关于如何将 CALayer 子类化为另一个 CALayer 掩码?的主要内容,如果未能解决你的问题,请参考以下文章
AFNetworking 2.0 - 如何从子类 AFHTTPSessionManager 成功将响应传递给另一个类