CAGradientLayer SetMask on CAShapeLayer crashes app
Using example code from many great people, I am able to make a complex shape using CAShapeLayer and present that no problem using a subclassed UIView:
@implementation BMTestLogo
+ (Class)layerClass {
return [CAShapeLayer class];
}
- (void)layoutSubviews {
[self setUpPaths];
[self setLayerProperties];
// [self attachAnimations];
}
- (void)setLayerProperties {
CAShapeLayer *layer = (CAShapeLayer *)self.layer;
// _gradient = [CAGradientLayer layer];
CGMutablePathRef combinedPath = CGPathCreateMutableCopy([[_UIBezierPathsArray objectAtIndex:0] CGPath]);
for (UIBezierPath* path in _UIBezierPathsArray) {
CGPathAddPath(combinedPath, NULL, path.CGPath);
}
layer.path = combinedPath;
layer.fillColor = [UIColor clearColor].CGColor;
layer.fillRule = kCAFillRuleEvenOdd;
}
This code works great, now trying to add a CAGradientLayer and mask over the shape, I keep getting a crash, specifically: QuartzCore CA::Layer::ensure_transaction_recursively(CA::Transaction*):
Here is the Gradient Code, note, this is taken from other, working examples on SO:
@implementation BMViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[_testLogo setNeedsDisplay];
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.startPoint = CGPointMake(0.5,1.0);
gradientLayer.endPoint = CGPointMake(0.5,0.0);
gradientLayer.frame = CGRectMake(CGRectGetMinX(_testLogo.layer.bounds), CGRectGetMinY(_testLogo.layer.bounds), CGRectGetWidth(_testLogo.layer.bounds), CGRectGetHeight(_testLogo.layer.bounds));
NSMutableArray *colors = [NSMutableArray array];
for (int i = 0; i < 2; i++) {
[colors addObject:(__bridge id)[UIColor colorWithHue:(0.1 * i) saturation:1 brightness:.8 alpha:1].CGColor];
}
gradientLayer.colors = colors;
NSNumber *stopOne = [NSNumber numberWithFloat:0.0];
NSNumber *stopTwo = [NSNumber numberWithFloat:1.0];
NSArray *locations = [NSArray arrayWithObjects:stopOne, stopTwo, nil];
gradientLayer.locations = locations;
gradientLayer.needsDisplayOnBoundsChange = YES;
[gradientLayer setMask:_testLogo.layer];
[_testLogo.layer insertSublayer:gradientLayer atIndex:0];
// Do any additional setup after loading the view, typically from a nib.
}
I have tried to debug and research this issue, and the usual suspects of the UIColors not being CGColors or (__bridge id) properly are not there, I am using two locations for the gradient, with only 2 colors, and moreover I have tried dozens of different versions: with or without setNeeds display, properties vs. local declarations, the gradient layer inside the sub class and out, all still giving me the same crash when inserting thesublayer.
When I take out the setMask: call, it does not crash, and just fills the whole frame with the gradient.
This seems like I'm just missing something minor or obvious. Note, using iOS 6 and ARC -- would like to keep using CAShapeLayer and CAGradientLayer as it makes it a bit easier to animate (which is the end goal).
The following code is triggering a stack overflow in ensure_transaction_recursively
.
[gradientLayer setMask:_testLogo.layer];
[_testLogo.layer insertSublayer:gradientLayer atIndex:0];
The shape layer has a gradient layer subview which has a shape layer mask which has a gradient layer subview...
Since your goal is to have a gradient layer that is masked by a shape, BMTestLogo
should be backed by the CAGradientLayer
which then has a the CAShapeLayer
as its mask. The shape layer should never reference the gradient layer.
上一篇: 以编程方式删除UIButton背景颜色