I' m trying to subclass CALayer
for use as a mask on another layer.
I want to use my CALayer
subclass in place of a CAGradientLayer
and use it for a gradient mask as explained here.
However I wish to use a custom CALayer
that uses an internal CGGradient
for drawing instead, as this should produce smoother results than CAGradientLayer
(see here). I don't care about performance, I want better gradient quality.
I'm following this example for creating my CGGradient
and storing it on the CALayer
.. However, I cannot get the mask to draw.
I don't know where to put the draw code: CALayer
's display
nor drawInContext:(CGContextRef)ctx
nor drawInContext:(CGContextRef)ctx
seem to be called when it is used as a mask.
Bear with me as I'm new with CoreAnimation. So, how to fix this so my CALayer
subclass works as a replacement for CAGradientLayer
but draws using a CGGradient
?
My current code here:
@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
And here is how I create it:
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;
If I use a CAGradientLayer
instead, it works fine (but the gradient looks bad).
Call -setNeedsDisplay
on your layer subclass before setting it to the mask and you'll only need to override -drawInContext:
of the CALayer
subclass. That will help you get the method to be called (CALayer calls -drawInContext:
using its default implementation of -display
which is called after -setNeedsDisplay
). You may also have to set the frame of the layer:
self.collectionViewTickerMaskLayer.frame = view.layer.bounds;
self.collectionViewTickerMaskLayer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
You have a logic issue in this code. You are using an endpoint which is CGPointZero, so even if the methods were called, no gradient would even be drawn to mask your layer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With