/
FaceView.m
137 lines (113 loc) · 3.84 KB
/
FaceView.m
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
//
// FaceView.m
// Happiness
//
// Created by admin on 3/D/12.
// Copyright (c) 2012 ThoughtAdvances. All rights reserved.
//
#import "FaceView.h"
@implementation FaceView
@synthesize scale = _scale; // Public @property must be @synthesized
#define DEFAULT_SCALE 0.90
- (CGFloat)scale {
if (!_scale) return DEFAULT_SCALE;
else return _scale;
}
- (void)setScale:(CGFloat)scale {
if (scale != _scale) { // setNeedsDisplay is expensive, check for change
_scale = scale;
[self setNeedsDisplay]; // If scale changed, update display
}
}
- (void)setup { // redraw
self.contentMode = UIViewContentModeRedraw;
}
- (void)awakeFromNib {
[self setup]; // redraw on load
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setup]; // redraw on init
}
return self;
}
- (void)drawCircleAtPoint:(CGPoint)p withRadius:(CGFloat)radius
inContext:(CGContextRef)context { // create a standard circle
UIGraphicsPushContext(context);
CGContextBeginPath(context);
CGContextAddArc(context, p.x, p.y, radius, 0, 2*M_PI, YES);
CGContextStrokePath(context);
UIGraphicsPopContext();
}
#define EYE_H 0.35
#define EYE_V 0.35
#define EYE_RADIUS 0.10
#define MOUTH_H 0.45
#define MOUTH_V 0.40
#define MOUTH_SMILE 0.25
- (void)drawRect:(CGRect)rect
{
// Anytime drawing is done, we need the context
CGContextRef context = UIGraphicsGetCurrentContext();
// Mouth definitions
CGPoint midPoint;
midPoint.x = self.bounds.origin.x + self.bounds.size.width/2;
midPoint.y = self.bounds.origin.y + self.bounds.size.height/2;
CGFloat size = self.bounds.size.width/2;
if (self.bounds.size.height < self.bounds.size.width) { //
size = self.bounds.size.height/2;
}
size *= self.scale;
CGContextSetLineWidth(context, 5.0);
[[UIColor blueColor] setStroke];
// Draw the face circle
[self drawCircleAtPoint:midPoint withRadius:size inContext:context];
// Eye definitions
CGPoint eyePoint;
eyePoint.x = midPoint.x - size * EYE_H;
eyePoint.y = midPoint.y - size * EYE_V;
// Draw the eye circles
[self drawCircleAtPoint:eyePoint withRadius:size * EYE_RADIUS
inContext:context];
eyePoint.x += size * EYE_H * 2;
[self drawCircleAtPoint:eyePoint withRadius:size * EYE_RADIUS
inContext:context];
// Mouth definitions
CGPoint mouthStart;
mouthStart.x = midPoint.x - MOUTH_H * size;
mouthStart.y = midPoint.y + MOUTH_V * size;
CGPoint mouthEnd = mouthStart;
mouthEnd.x += MOUTH_H * size * 2;
CGPoint mouthCP1 = mouthStart;
mouthCP1.x += (mouthEnd.x - mouthStart.x)/3;
CGPoint mouthCP2 = mouthEnd;
mouthCP2.x -= (mouthEnd.x - mouthStart.x)/3;
// Get the smile value from some data source
float smile = [self.dataSource smileForFaceView:self];
// Protect again invalid data
if (smile < -1) smile = -1;
if (smile > 1) smile = 1;
// Curve offset
CGFloat smileOffset = MOUTH_SMILE * size * smile;
mouthCP1.y += smileOffset;
// Draw the mouth
CGContextBeginPath(context);
CGContextMoveToPoint(context, mouthStart.x, mouthStart.y);
// The control point y values are always the same
CGContextAddCurveToPoint(context, mouthCP1.x, mouthCP1.y, mouthCP2.x,
mouthCP1.y, mouthEnd.x, mouthEnd.y);
CGContextStrokePath(context);
}
// Pinch to scale the face
// This is what it should do when it recieves the signal that the pinch
// gesture has occurred
- (void)pinch:(UIPinchGestureRecognizer *)gesture {
if ((gesture.state == UIGestureRecognizerStateChanged) ||
(gesture.state == UIGestureRecognizerStateEnded)) {
self.scale *= gesture.scale;
gesture.scale = 1; // reset the gesture to 1
}
}
@end