-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathFaceView.swift
151 lines (119 loc) · 4.51 KB
/
FaceView.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//
// FaceView.swift
// Happiness
//
// Created by Géza Mikló on 04/03/15.
// Copyright (c) 2015 Géza Mikló. All rights reserved.
//
import UIKit
protocol FaceViewDataSource : class {
func smilinessForFaceView(sender: FaceView) -> Double?
}
@IBDesignable
class FaceView: UIView {
@IBInspectable
var lineWidth: CGFloat = 3
@IBInspectable
var scale: CGFloat = 0.9 {
didSet {
setNeedsDisplay()
}
}
var rotation : CGFloat = 0 {
didSet {
transform = CGAffineTransformMakeRotation(rotation)
setNeedsDisplay()
}
}
/*var smiliness : Double = 0.6 {
didSet {
setNeedsDisplay()
}
}*/
weak var dataSource: FaceViewDataSource?
private enum Eye { case Left, Right }
@IBInspectable
var faceColor: UIColor = UIColor.redColor()
var faceCenter : CGPoint {
return convertPoint(center, fromView: superview)
}
var eyeRadius : CGFloat {
return faceRadius / Scaling.FaceRadiusToEyeRadiusRatio
}
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
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func drawRect(rect: CGRect) {
println("Drawing")
// Drawing code
faceColor.setStroke()
let facePath = UIBezierPath(arcCenter: faceCenter, radius: faceRadius, startAngle: 0, endAngle: CGFloat(2*M_PI), clockwise: true)
facePath.lineWidth = lineWidth
facePath.stroke()
let leftEyePath = bezierPathForEye(.Left)
leftEyePath.stroke()
let rightEyePath = bezierPathForEye(.Right)
rightEyePath.stroke()
let smiliness = dataSource?.smilinessForFaceView(self) ?? 0.0
let smilePath = bezierPathForSmile(smiliness)
smilePath.stroke()
}
private func bezierPathForEye(whichEye: Eye) -> UIBezierPath {
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 eyePath = UIBezierPath(arcCenter: eyeCenter, radius: eyeRadius, startAngle: 0, endAngle: CGFloat(2*M_PI), clockwise: true)
eyePath.lineWidth = lineWidth
return eyePath;
}
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
}
func onPinched(gesture: UIPinchGestureRecognizer) {
switch gesture.state {
case .Changed:
scale = gesture.scale * scale
gesture.scale = 1
default:
break
}
}
func onRotate(gesture: UIRotationGestureRecognizer) {
switch gesture.state {
case .Changed:
rotation += gesture.rotation
gesture.rotation = 0
default:
break
}
}
}