Search code examples
iosiphonequartz-graphicscgcontextcglayer

How to draw to multiple CGLayers at the same time?


I'd like to draw objects to two separate CGLayers from within the same for loop, but am unsure how to do this.

For example, I'd like to draw three orange circles behind three blue circles, with the orange circles in one layer, and the blue circles in another. The following code will place each circle on top of the previous circle:

-(void) drawRect:(CGRect)rect {
    UIBezierPath *circle;
    for (int i = 1; i <= 3; i++) {
        // Create an orange circle
        circle = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(CGRectMake(i*50, 80, 50, 50), 0, 0)];
        circle.lineWidth = 4.0f;
        [[UIColor colorWithRed:1.0 green:0.75 blue:0 alpha:1.0] setFill];
        [[UIColor orangeColor] setStroke];
        [circle stroke];
        [circle fill];

        // Create a blue circle
        circle = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(CGRectMake(25 + i*50, 80, 50, 50), 0, 0)];
        circle.lineWidth = 4.0f;
        [[UIColor colorWithRed:0 green:0.5 blue:1.0 alpha:1.0] setFill];
        [[UIColor blueColor] setStroke];
        [circle stroke];
        [circle fill];
    }
}

Output from the code above

How would I modify this so that the three orange circles would end up in an orangeLayer that sits behind the three blue circles in a blueLayer? I imagine this has something to do with saving and restoring contexts, but I can't really wrap my head around it.

Thanks so much!

PS: I realize that I can simply draw using two for loops inline to achieve the right effect, but this example is for instructional purposes to learn layering. Thanks!


Solution

  • I build a custom subclass of UIView, and create a function makeCircleWithFrame to draw a circle inside a view using UIGraphicsBeginImageContextWithOptions, i believe it will solve your main problem:

    #import "circleView.h"
    #import <math.h>
    
    @implementation circleView
    
    - (id)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (!self) return self;
    
        [self setupViews];
    
        return self;
    }
    
    - (void)awakeFromNib
    {
        [self setupViews];
    }
    
    - (void)setupViews
    {
        [self setBackgroundColor:[UIColor whiteColor]];
    
    
        for (int i = 1; i <= 6; i++) {
    
            UIColor *circleColor;
    
            //Math function just to set different colors for each circle
            if (fmodf(i, 2) == 0) {
                circleColor = [UIColor colorWithRed:1.0 green:0.75 blue:0 alpha:1.0];
            }
            else {
                circleColor = [UIColor colorWithRed:0 green:0.5 blue:1.0 alpha:1.0];
            }
    
    
            UIView *circleView = [self makeCircleWithFrame:(CGRectMake(10*i, 10*i, 100, 100)) andFillColor:circleColor];
            circleView.tag = i;
            NSLog(@"circle %i", i);
        }
    }
    
    - (UIView *)makeCircleWithFrame:(CGRect)rect andFillColor:(UIColor *)color {
        // declare UIimageView, not UIView
        UIImageView *customView = [[UIImageView alloc] init];
        customView.frame= self.bounds;
    
        // create a new contex to draw
        UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 200), NO, 0);
    
        UIBezierPath *grayCircle = [UIBezierPath bezierPathWithOvalInRect:rect];
    
        grayCircle.lineWidth = 6;
        [color setFill];
        [[UIColor orangeColor] setStroke];
        [grayCircle stroke];
        [grayCircle fill];
    
        customView.image = UIGraphicsGetImageFromCurrentImageContext();
    
        UIGraphicsEndImageContext();
    
        [self addSubview:customView];
    
        return customView;
    }
    

    Please give me a feedback if you still having problems or need anymore help.