Skip to content

Instantly share code, notes, and snippets.

@john4
Created July 14, 2015 22:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save john4/b3b465ef736c18103a61 to your computer and use it in GitHub Desktop.
Save john4/b3b465ef736c18103a61 to your computer and use it in GitHub Desktop.
Stanford: Developing iOS8 Apps with Swift
//
// FaceView.swift
// drawTest
//
// Created by John Martin on 7/14/15.
// Copyright (c) 2015 John Martin. All rights reserved.
//
import UIKit
class FaceView: UIView {
var lineWidth: CGFloat = 3 { didSet { setNeedsDisplay() } }
var color: UIColor = UIColor.blueColor() { didSet { setNeedsDisplay() } }
var scale: CGFloat = 0.90 { didSet { setNeedsDisplay() } }
var faceCenter: CGPoint {
// get {
// CALCULATED ONLY
// }
return convertPoint(center, fromView: superview)
}
var faceRadius: CGFloat {
return min(bounds.size.width, bounds.size.height) / 2 * scale
}
private struct Scaling{
static let FaceRadiusToEyeRadiusRatio: CGFloat = 10
static let FaceRadiusToEyeOffsetRatio: CGFloat = 3
static let FaceRadiusToEyeSeparationRatio: CGFloat = 1.5
static let FaceRadiusToMouthWidthRatio: CGFloat = 1
static let FaceRadiusToMouthHeightRatio: CGFloat = 3
static let FaceRadiusToMouthOffsetRatio: CGFloat = 3
}
private enum Eye { case Left, Right }
private func bezierPathForEye(whichEye: Eye) -> UIBezierPath {
let eyeRadius = faceRadius / Scaling.FaceRadiusToEyeRadiusRatio
let eyeVerticalOffset = faceRadius / Scaling.FaceRadiusToEyeOffsetRatio
let eyeHorizontalSeparation = faceRadius / Scaling.FaceRadiusToEyeSeparationRatio
var eyeCenter = faceCenter
eyeCenter.y -= eyeVerticalOffset
switch whichEye {
case .Left: eyeCenter.x -= eyeHorizontalSeparation / 2
case .Right: eyeCenter.x += eyeHorizontalSeparation / 2
}
let path = UIBezierPath(arcCenter: eyeCenter, radius: eyeRadius, startAngle: 0, endAngle: CGFloat(2*M_PI), clockwise: true)
path.lineWidth = lineWidth
return path
}
private func bezierPathForSmile(fractionOfMaxSmile: Double) -> UIBezierPath {
let mouthWidth = faceRadius / Scaling.FaceRadiusToMouthWidthRatio
let mouthHeight = faceRadius / Scaling.FaceRadiusToMouthHeightRatio
let mouthVerticalOffset = faceRadius / Scaling.FaceRadiusToMouthOffsetRatio
let smileHeight = CGFloat(max(min(fractionOfMaxSmile, 1), -1)) * mouthHeight
let start = CGPoint(x: faceCenter.x - mouthWidth / 2, y: faceCenter.y + mouthVerticalOffset)
let end = CGPoint(x: start.x + mouthWidth, y: start.y)
let cp1 = CGPoint(x: start.x + mouthWidth / 3, y: start.y + smileHeight)
let cp2 = CGPoint(x: end.x - mouthWidth / 3, y: cp1.y)
let path = UIBezierPath()
path.moveToPoint(start)
path.addCurveToPoint(end, controlPoint1: cp1, controlPoint2: cp2)
path.lineWidth = lineWidth
return path
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func drawRect(rect: CGRect) {
let facePath = UIBezierPath(arcCenter: faceCenter, radius: faceRadius, startAngle: 0, endAngle: CGFloat(2*M_PI), clockwise: true)
facePath.lineWidth = lineWidth
color.set()
facePath.stroke()
bezierPathForEye(.Left).stroke()
bezierPathForEye(.Right).stroke()
let smiliness = -0.75
let smilePath = bezierPathForSmile(smiliness)
smilePath.stroke()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment