Silver Challenge in Swift


#1

Please let me know of any improvements that could be made!

AppDelegate.swift

[code]//
// AppDelegate.swift
// Hypnosister
//
// Created by adam on 6/13/14.
// Copyright © 2014 Adam Schoonmaker. All rights reserved.
//

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UIScrollViewDelegate {

var window: UIWindow?

var hypnosisView = HypnosisView(frame: CGRectMake(0.0, 0.0, 0.0, 0.0))

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
    self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
    // Override point for customization after application launch.
    
    // Create CGRects for frames
    var screenRect = self.window!.bounds
    var bigRect = screenRect
    bigRect.size.width *= 2.0
    //bigRect.size.height *= 2.0
    
    // Create a screen-sized scroll view and add it to the window
    // (used for example of paging)
    let scrollView = UIScrollView(frame: screenRect)
    // Paging works by taking the size of a scroll view's "bounds" and
    // dividing up the "contentSize" it displays into sections of the same 
    // size. When the user pans, the view port scrolls to show only one of
    // the sections
    //scrollView.pagingEnabled = true
    // paging must be off for pinch to zoom
    scrollView.pagingEnabled = false
    scrollView.delegate = self
    scrollView.maximumZoomScale = 2.0
    scrollView.minimumZoomScale = 0.5
    
    self.window!.addSubview(scrollView)
    
    /*
    // Create a super-sized hypnosis ciew and add it to the scroll view
    // (used for example of panning)
    let hypnosisView = HypnosisView(frame: bigRect)
    scrollView.addSubview(hypnosisView)
    */
    
    // Create a screen-sized hypnosis view and add it to the scroll view
    // (used for example of paging)
    hypnosisView = HypnosisView(frame: screenRect)
    scrollView.addSubview(hypnosisView)
    
    // Add a second screen-sized hypnosis view just off the screen to the right
    screenRect.origin.x += screenRect.size.width
    let anotherHypnosisView = HypnosisView(frame: screenRect)
    scrollView.addSubview(anotherHypnosisView)
    
    
    // Tell the scroll view how big its content area is
    scrollView.contentSize = bigRect.size
    
    
    // intialize the HypnosicView with size of firstFrame, set bg to red
    // the values are in points; not pixels. retina display: point = .5px, on non-retina: point = 1px
    // frame is relative to the super view, in this case window
    //let firstFrame = CGRectMake(160, 240, 100, 150)
    /*
    let firstFrame: CGRect = self.window!.bounds
    let firstView: HypnosisView = HypnosisView(frame: firstFrame)
    // adds the HypnosisView as a subview of the window to make it part of the view hierarchy
    self.window!.addSubview(firstView)
    */
    
    /*
    // create a new HypnosisView, make it a subview of the first Hyposis view
    // frame is relative to the super view, in this case "firstView"
    let secondFrame = CGRectMake(20, 30, 50, 50)
    let secondView = HypnosisView(frame: secondFrame)
    secondView.backgroundColor = UIColor.blueColor()
    firstView.addSubview(secondView)
    */
    
    
    
    self.window!.backgroundColor = UIColor.whiteColor()
    self.window!.makeKeyAndVisible()
    return true
}

func viewForZoomingInScrollView(scrollView: UIScrollView!) -> UIView! {
    return hypnosisView
}

// …
}
[/code]

HypnosisView.swift

//
//  HypnosisView.swift
//  Hypnosister
//
//  Created by adam on 6/13/14.
//  Copyright (c) 2014 Adam Schoonmaker. All rights reserved.
//

import UIKit

class HypnosisView: UIView {

    var circleColor = UIColor.lightGrayColor()
    
    
    func setCircleColor(circleColor color: UIColor) {
        
        self.circleColor = color
        self.setNeedsDisplay()
    }
    
    
    init(frame: CGRect) {
        super.init(frame: frame)
        // Initialization code
        
        // All HypnosisViews start with a clear background color
        // (a view's backgroundColor is drawn regardless of what drawRect does,
        // so often custom views are set to have a transparent background so that
        // only the results of drawRect show
        self.backgroundColor = UIColor.clearColor()
    }
    
    
    // Only override drawRect: if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func drawRect(rect: CGRect)
    {
        // First thing to do when overriding this: get the bounds
        let bounds = self.bounds
        
        // Figure out the center of the bounds rectangle
        let center = CGPoint(x: (bounds.origin.x + bounds.size.width / 2.0),
            y: (bounds.origin.y + bounds.size.height / 2.0))
        
        // The largest circle will circumscribe the view
        let maxRadius = hypot(bounds.size.width, bounds.size.height) / 2.0
        
        // Draw the circle using UIBezierPath; draws lines and curves to make shapes
        let path = UIBezierPath()
        
        // Could have multiple instances of UIBezierPath, each one being one circle, 
        // or add multiple circles to a single instance. slightly more effcient w/ single instance
        for var currentRadius = maxRadius; currentRadius > 0; currentRadius -= 20 {
            
            // "pick up" the "pencil" and move it to the correct starting spot
            path.moveToPoint(CGPointMake(center.x + currentRadius, center.y))
            
            path.addArcWithCenter(center, radius: currentRadius, startAngle: 0,
                endAngle: M_PI * 2.0, clockwise: true)
            println("drawing circle... x:\(center.x)   y:\(center.y)   radius:\(currentRadius)")
        }
        
        // Make the line width 10 points
        path.lineWidth = 10
        
        // Sets the color of subsequent stroke operations to the color that the receiver represents
        circleColor.setStroke()
        
        // Draw the line!
        path.stroke()
        
        

        // Shadows cannot be "unset", so the current context must be saved and
        // restored from after the shawdow is used
        var baseContext = UIGraphicsGetCurrentContext()
        CGContextSaveGState(baseContext)
        
        // Calculate values to use for drawing the logo
        let logoRectWidth = bounds.size.width / 2.0
        let logoRectHeight = bounds.size.height / 2.0
        let logoRectOriginX = logoRectWidth / 2.0
        let logoRectOriginY = logoRectHeight / 2.0
        
        
        
        // Draw a triangle path using the logo calculated values
        let triangleTop = CGPointMake(logoRectWidth, logoRectOriginY - 20.0)
        let triangleBottomLeft = CGPointMake(logoRectOriginX - 10.0,
            logoRectOriginY + logoRectHeight + 20.0)
        let triangleBottomRight = CGPointMake(logoRectOriginX + logoRectWidth + 10.0,
            logoRectOriginY + logoRectHeight + 20.0)
        let triangleBottomMiddle = CGPointMake(logoRectWidth,
            logoRectOriginY + logoRectHeight + 20.0)
        
        // Set "pencil" down at the top of the triangle, then draw the edges
        let trianglePath = UIBezierPath()
        trianglePath.moveToPoint(triangleTop)
        trianglePath.addLineToPoint(triangleBottomLeft)
        trianglePath.addLineToPoint(triangleBottomRight)
        trianglePath.addLineToPoint(triangleTop)
        //trianglePath.stroke()
        
        // Use the triangle path to draw a gradient
        // Gradients cover everything in the view, so a clipping path must be 
        // installed on the graphics context that defines what the gradient covers
        trianglePath.addClip()
        
        // Create the gradient
        let locations: CGFloat[] = [0.0, 1.0]
        let components: CGFloat[] = [ 0.0, 1.0, 0.0, 1.0, // Start color: green
                                        1.0, 1.0, 0.0, 1.0] // End color: yellow
        var colorspace = CGColorSpaceCreateDeviceRGB()
        var gradient = CGGradientCreateWithColorComponents(colorspace, components,
            locations, 2)
        
        // Draw the gradient
        CGContextDrawLinearGradient(baseContext, gradient, triangleTop,
            triangleBottomMiddle, 0)
        
        // Deallocate (note: make sure gradient and colorspace are defined with
        // "var" instead of "let", or else this will give an error
        //CGGradientRelease(gradient)
        //CGColorSpaceRelease(colorspace)
        
        // Restore the graphics state to clear the clip path
        CGContextRestoreGState(baseContext)
    
        
        
        baseContext = UIGraphicsGetCurrentContext()
        CGContextSaveGState(baseContext)
        // Now anything drawn will appear with a shadow
        CGContextSetShadow(baseContext, CGSizeMake(4, 7), 3)
        
        // Create UIImage object from logo.png imported file, draw it over circles
        let logoImage = UIImage(named: "logo.png")
        
        logoImage.drawInRect(CGRect(x: logoRectOriginX, y: logoRectOriginY,
            width: logoRectWidth, height: logoRectHeight))
        
        // Now anything drawn won't have a shadow
        CGContextRestoreGState(baseContext)
    }
    
    
    // When a finger touches the view; this is a touch event handler
    override func touchesBegan(touches: NSSet!, withEvent event: UIEvent!) {
        
        println("\(self) was touched")
        
        // Get 3 random numbers between 0 and 1
        let red = Double(arc4random() % 100) / 100.0
        let green = Double(arc4random() % 100) / 100.0
        let blue = Double(arc4random() % 100) / 100.0
        
        let randomColor = UIColor(red: red, green: green, blue: blue, alpha: 1.0)
        
        setCircleColor(circleColor: randomColor)
    }

}