Gold Solution


#1

First of all, I really liked this challenge. Lots of thinking and research. Here’s my solution.

LogoView.h

#import <Foundation/Foundation.h>

@interface LogoView : UIView

{
    
}

-(id)initWithFrame:(CGRect)frame;

@end

LogoView.m

#import "LogoView.h"

@implementation LogoView

-(id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    
    if (self)
    {
        [self setBackgroundColor:[UIColor clearColor]];
    }
    
    return self;
    
}

-(void)drawRect:(CGRect)rect
{
    CGContextRef lvCTX = UIGraphicsGetCurrentContext();
    CGRect bounds = [self bounds];
    
    CGPoint center;
    center.x = bounds.origin.x + bounds.size.width/2.0;
    center.y = bounds.origin.y + bounds.size.height/2.0;
    CGSize size = bounds.size;

    
    //Create a smaller rect for the logo portion and the clipping circle size. The larger rect allows the shadow show to show through.
    float smallRect = size.width * 0.667;
    CGRect logoRect = CGRectMake(center.x - smallRect/2.0, center.y - smallRect/2.0, smallRect, smallRect);
    CGSize logoSize = logoRect.size;
    
    
//Used to verify calculations. not needed any more
//    CGPoint logoCenter;
//    logoCenter.x = logoRect.origin.x + logoRect.size.width / 2.0;
//    logoCenter.y = logoRect.origin.y + logoRect.size.height / 2.0;
//    
//    NSLog(@"bound center x,y = %f %f", center.x, center.y);
//
//    NSLog(@"small center x,y = %f %f", logoCenter.x, logoCenter.y);

//Create the shadow in the main rect which is larger than logoRect. The circle needs to be the same size as the clipping circle.
    //Save the graphics state first
    CGContextSaveGState(lvCTX);

    //Make the shadow
    CGSize offset = CGSizeMake(2, 2);
    CGColorRef color = [[UIColor darkGrayColor] CGColor];
    CGContextSetShadowWithColor(lvCTX, offset, 3, color);

    //Create the circle to create the shadow
    CGContextSetStrokeColorWithColor(lvCTX, [[UIColor blackColor] CGColor]);
    CGContextAddArc(lvCTX, center.x, center.y, logoSize.width/2.0, 0, M_PI*2.0, YES);
    CGContextStrokePath(lvCTX);

    //Restore graphics state
    CGContextRestoreGState(lvCTX);
    
//Create the clipping function. All drawing from here will be clipped to the circle
    CGContextAddArc(lvCTX, center.x, center.y, logoSize.width/2.0, 0, M_PI*2.0, YES);
    CGContextClip(lvCTX);
    
    
//Add the image
    UIImage *logo = [UIImage imageNamed:@"icon.png"];
    [logo drawInRect];
    
     
//Create Gradient
    //Start with the colorspace
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    
    //Create the colors
    float colors[8] =
    {
        0.00f, 0.00f, 0.90f, 0.5f,
        1.00f, 1.00f, 1.00f, 0.25f
    };
    
    //Start and endpoints: top center to middle center
    CGPoint startPoint = CGPointMake(center.x, 0.0);
    CGPoint endPoint   = CGPointMake(center.x, center.y);
    
    //Create the gradient object
    CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, colors, NULL, 2);
    
    
    //Draw the gradient
    CGContextDrawLinearGradient(lvCTX, gradient, startPoint, endPoint, kCGGradientDrawsAfterEndLocation);
}

@end

The additional rect allows one to vary the initialization parameters as opposed to hard coding the clipping circle etc.

Comments appreciated.


#2

I couldn’t complete this challenge after trying it - so I took a look at your code.

Very nice work. :smiley:


#3

Thanks, Tander. Glad to help out a fellow student.


#4

Your solution totally helped me out in getting the subclassing done. Thanks for posting!


#5

Thanks, tokyomike. Anytime I can give back is awesome.

Jeff