Challenge solutions


#1

Here is my code for the three challenges. Seems to work ok. Not sure if using rand is the best way to generate random values for ring colours, but it looks pretty. Also added in a graduated alpha value in the for loop for some variety.
Can’t work out why my logo is imported upside down and mirrored! Performed an AffineTransform at the start of logoView.m, which looks fine, but seems clunky, and I think it messes with the normal orientation of the y axis…any thoughts?

HypnosisterAppDelegate.h

#import <UIKit/UIKit.h>
#import "HypnosisView.h"
#import "LogoView.h"

@interface HypnosisterAppDelegate : UIResponder <UIApplicationDelegate,UIScrollViewDelegate>
{
    HypnosisView *view;
    LogoView *logoView;
}

@property (strong, nonatomic) UIWindow *window;

@end

HypnosisterAppDelegate.m

#import "HypnosisterAppDelegate.h"
#import "HypnosisView.h"
#import "LogoView.h"

@implementation HypnosisterAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    
    [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade];
    
//Create a rect from the window bounds to send as an argument to Hypnosis view's init
    CGRect screenRect=[[self window]bounds];
    
//Instantiate a Hypnosis View
    view=[[HypnosisView alloc]initWithFrame:screenRect];
    
//Create a rect to hold the logo, larger than the logo size(80 x 80)
//to accomodate the shadow
    CGRect lrect=CGRectMake(10, 10, 90, 90);
    
//Instantiate a logo view
    logoView = [[LogoView alloc]initWithFrame:lrect];
    
//Make it a subview of the Hypnosis view
    [view addSubview];

//Add the HypnosisView as a subview of the window view
    [self.window addSubview:view];
    
//Make Hypnosis view first responder for shaking
    BOOL success=[view becomeFirstResponder];
    if (success) {
    NSLog(@"Hypnosis view became first responder");
          }else{
              NSLog(@"cound not become first responder");
          }

//Set window's background colour
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    
    return YES;
}

@end

HypnosisView.h

[code]
#import <Foundation/Foundation.h>

@interface HypnosisView : UIView

@end[/code]

HypnosisView.m

[code]
#import “HypnosisView.h”

@implementation HypnosisView

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

return self;

}

-(void)drawRect:(CGRect)dirtyRect
{
//Declare a CGContext
CGContextRef ctx=UIGraphicsGetCurrentContext();

//Declare a CGRect the size of the view
CGRect bounds = [self bounds];

//Figure out the centre of the bounds rectangle
CGPoint center;
center.x = bounds.origin.x+bounds.size.width/2;
center.y = bounds.origin.y+bounds.size.height/2;

//The radius of the circle should be nearly as big as the view - declare it
float maxRadius = hypot(bounds.size.width, bounds.size.height)/2.0;

//The thickness of the line should be 10pts wide
CGContextSetLineWidth(ctx, 10);

//Add concentric rings to the context and stroke them with random colours

for (float currentRadius=maxRadius; currentRadius>0; currentRadius-=20) {
    [[UIColor colorWithRed:(float)(rand()%100)/100 green:(float)(rand()%100)/100 blue:(float)(rand()%100)/100 alpha:currentRadius/maxRadius] setStroke];
    //Add a path to the context
    CGContextAddArc(ctx, center.x, center.y, currentRadius, 0.0, M_PI*2.0, YES);
    //Perform drawing action and remove path
    CGContextStrokePath(ctx);
}

//Create a string
NSString *text=@“You are getting sleepy”;

//Get a font to draw it in
UIFont *font = [UIFont boldSystemFontOfSize:28];

//Declare a rect to draw string inside
CGRect textRect;

//How big is this string when drawn in this font?
textRect.size=[text sizeWithAttributes:@{NSFontAttributeName:font}];

//Put the string in the center of the view
textRect.origin.x=center.x-textRect.size.width/2.0;
textRect.origin.y=center.y-textRect.size.height/2.0;

//Set the fill colour of the current context to black
[[UIColor colorWithRed:0.6 green:0.6 blue:0.6 alpha:0.5]setFill];

//The shadow iwll move 4 poiunts to the right and three points down
CGSize offset = CGSizeMake(4, 3);

//The shadow will be dark grey in colour
CGColorRef color=[[UIColor darkGrayColor]CGColor];

//Set the shadow of the context with these parameters
//all subsequent drawing will be shadowed
CGContextSetShadowWithColor(ctx, offset, 5.0, color);

//Draw the string
[text drawInRect:textRect withAttributes:@{NSFontAttributeName:font}];

//Save the current state
CGContextSaveGState(ctx);

//Create new state
CGContextSetLineWidth(ctx, 1);
[[UIColor greenColor] setStroke];
CGContextSetShadowWithColor(ctx, offset, 0,[[UIColor colorWithWhite:0 alpha:0]CGColor]);

//Draw cross hairs
CGContextMoveToPoint(ctx, center.x, center.y-20);
CGContextAddLineToPoint(ctx, center.x, center.y+20);
CGContextStrokePath(ctx);
CGContextMoveToPoint(ctx, center.x-20, center.y);
CGContextAddLineToPoint(ctx, center.x+20, center.y);
CGContextStrokePath(ctx);

//Restore previous state
CGContextRestoreGState(ctx);

}
//Enable the view as first responder for shaking
-(BOOL)canBecomeFirstResponder
{
return YES;
}
//method to refresh view on shaking - redraws random colours
-(void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if (motion==UIEventSubtypeMotionShake) {
NSLog(@“Device started shaking!”);
[self setNeedsDisplay];
}
}

@end[/code]

LogoView.h

[code]
#import <UIKit/UIKit.h>

@interface LogoView : UIView

@end[/code]

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
{
//Declare a new graphics context
    CGContextRef lctx=UIGraphicsGetCurrentContext();

//Get the logo image and declare its CGImage variable
    UIImage *logo=[UIImage imageNamed:@"Icon@80"];
    CGImageRef logoRef=logo.CGImage;

//Declare a rect to draw in(larger than image draw rect to accomodate shadow
    CGRect viewRect = [self bounds];
    
//Declare smaller rect to draw image in, the size of the image
    CGRect logoRect=CGRectMake(5,5, viewRect.size.width-10, viewRect.size.height-10);

//Rotate 180degrees
    CGAffineTransform rotate=CGAffineTransformMakeRotation(M_PI);
    [self setTransform:rotate];
    
//Set normal blend mode and save context
    CGContextSetBlendMode(lctx, kCGBlendModeNormal);
    CGContextSaveGState(lctx);
    
//Set Shadow for disc
    CGSize offset=CGSizeMake(0, -2);
    CGColorRef shadowColor=[[UIColor darkGrayColor]CGColor];
    CGContextSetShadowWithColor(lctx, offset, 3.0, shadowColor);
    
//Draw white disc
    CGContextAddArc(lctx, 45, 45, 40, 0, M_PI*2, 0);
    [[UIColor whiteColor]setFill];
    CGContextFillPath(lctx);
    
//Restore state (no shadow)
    CGContextRestoreGState(lctx);

//Draw outline
    CGContextSetLineWidth(lctx, 1);
    [[UIColor blackColor]setStroke];
    CGContextAddArc(lctx, 45, 45, 40, 0, M_PI*2, 0);
    CGContextStrokePath(lctx);
    
//Create clipping path for image
    CGContextAddArc (lctx, viewRect.size.width/2,viewRect.size.height/2, 40, 0, M_PI*2, 0);
    CGContextClip (lctx);
    
//Save new state?
    CGContextSaveGState(lctx);
    
//Declare gradient object and color space
    CGGradientRef gradient;
    CGColorSpaceRef cSpace;
    CGAffineTransform myTransform;//for scaling gradient locations
    cSpace = CGColorSpaceCreateDeviceRGB();
    
//Define gradient
    CGFloat locations [2]={0.0,0.5};
    CGFloat components [8]={0.8,0.8,1.0,1.0,1.0,1.0,1.0,1.0};
    gradient = CGGradientCreateWithColorComponents(cSpace, components, locations, 2);
    CGPoint endPoint= CGPointMake(0.5, 0.0);
    CGPoint startPoint= CGPointMake(0.5, 1.0);
    
//Draw gradient
    myTransform = CGAffineTransformMakeScale (viewRect.size.width, viewRect.size.height);
    CGContextConcatCTM (lctx, myTransform);
    CGContextSetBlendMode(lctx, kCGBlendModeMultiply);
    CGContextDrawLinearGradient(lctx, gradient, startPoint, endPoint, 0);
 
//Restore state with clipping path and draw image
    CGContextRestoreGState(lctx);
    CGContextSetBlendMode(lctx, kCGBlendModeMultiply);
    CGContextDrawImage(lctx, logoRect, logoRef);
   
    
}


@end