Domanda

I'm using this sample code from Palimondo: it is brilliant code learning how to mask CAGradientLayer's onto CAShapeLayers. The Output is as follows:

enter image description here

Now I am trying to create this image:

enter image description here

Using PaintCode, I was able to get all the UIBezierPath's and Gradient Colors and stops and put them into multiple Arrays, and essentially iterate through each one adding it to new CAShapeLayer and CAGradientLayer as such:

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self blackPaths];
    [self setupGradients];
    int count = 0;
    for (CAGradientLayer *gradientLayerItem in _individualGradientArrays) {

        CAShapeLayer *gradientMask = [CAShapeLayer layer];
        gradientMask.fillColor = [[UIColor clearColor] CGColor];
        gradientMask.strokeColor = [[UIColor blackColor] CGColor];
        gradientMask.lineWidth = 4;
        gradientMask.frame = CGRectMake(0, 0, _testView.bounds.size.width, _testView.bounds.size.height);
        //
        //    CGMutablePathRef t = CGPathCreateMutable();
        //    CGPathMoveToPoint(t, NULL, 0, 0);
        //    CGPathAddLineToPoint(t, NULL, _testView.bounds.size.width, _testView.bounds.size.height);

        gradientMask.path = [[_UIBezierPathsArray objectAtIndex:count]CGPath];


        CAGradientLayer *gradientLayer = [CAGradientLayer layer];
        gradientLayer.locations = gradientLayerItem.locations;
        gradientLayer.startPoint = CGPointMake(0.5,1.0);
        gradientLayer.endPoint = CGPointMake(1.0,0.5);
        gradientLayer.frame = CGRectMake(0, 0, _testView.bounds.size.width, _testView.bounds.size.height);
        //    NSMutableArray *colors = [NSMutableArray array];
        //    for (int i = 0; i < 3; i++) {
        //        [colors addObject:(id)[[UIColor colorWithHue:(0.2 * i) saturation:1 brightness:.8 alpha:1] CGColor]];
        //    }
        gradientLayer.colors = gradientLayerItem.colors;

        [gradientLayer setMask:gradientMask];
        [_testView.layer addSublayer:gradientLayer];
        count++;
    }

[_testView setNeedsDisplay];

The goal is to have 16 individual CAGradientLayer's that I can animate using CoreAnimation to create a sort of "swirling" effect (I could just place the output from PaintCode into a drawRect, and it works, the problem is that I was told that I would have a much more difficult time animating either the colors or gradients via CoreGraphics rather than placing them in Layers).

And then, this is outputed:

The 70's dance party version...

After 100's of iterations and before this point, I tried swaping out the [UIColor clearColor] for whiteColor (Which is not what the sample code required) and this is outputted:

almost there...

You can see there is only a couple of gradients, and it is my belief the whiteColor is interfering with the CAGradientLayer.

I know I must be missing something extremely subtle, but I can't seem to see it.

Why is it that in the example code, we are able to use clearColor and have the gradient show up appropriately, yet using clearColor with my UIBezierPath's attached to my CAShapeLayer's the gradients break?

A friend mentioned that another solution would be to have 3 circles of the gradients and basically rotate them concentrically over the masked shape creating the illusion, however I am at a loss how I would be able to do that.

È stato utile?

Soluzione

It's hard to say from what's here exactly what's going on. In the third picture (based on your code) you're drawing opaque, black strokes around a clear fill into the mask, so when you use that as a mask, only the areas you stroked will be "visible" from the gradient layer (the hint that these are strokes only is that you can see the stroke miters). When you change clearColor to whiteColor (which is opaque), the area inside the path also becomes visible from the gradient layer (the hint to this is that the lines appear fatter owing to the fact that the stroke runs along the middle of the path, thus "fattening" the fill. Also the stroke miters are no longer visible because they've been occluded by the fill.)

In a mask layer, the color is irrelevant -- it's the alpha channel (opacity) that matters. This is why whiteColor vs. blackColor makes no difference. They both have an alpha value of 1.0, whereas clearColor has an alpha value of 0.0. From the header:

/* A layer whose alpha channel is used as a mask to select between the
 * layer's background and the result of compositing the layer's
 * contents with its filtered background. Defaults to nil. When used as
 * a mask the layer's `compositingFilter' and `backgroundFilters'
 * properties are ignored. When setting the mask to a new layer, the
 * new layer must have a nil superlayer, otherwise the behavior is
 * undefined. */

@property(retain) CALayer *mask;

This is why you no longer see the stroke miters in the fourth image -- they're being hidden by the fact that the mask only looks at the alpha channel and regardless of color hue (i.e. white or black) they both paint with an alpha of 1.0.

Again, it's not clear exactly what you're trying to do here in the end, but your use of whiteColor feels like a red herring. If your goal is something that looks like the second image, you probably want your mask layer to have no stroke and an opaque fill, as in:

gradientMask.fillColor = [[UIColor blackColor] CGColor];
gradientMask.strokeColor = [[UIColor clearColor] CGColor];
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top