Drawing with Core Graphics
MovingSmiles example
MovingSmiles
Core Graphics
&
Gesture Recognizers
Core Graphics
Top facts:
Demo - MovingSmiles
MovingSmilesViewController
New File... UIViewController (without a .xib)
Universal app setup
App delegate headers
App delegate implementation files
MainWindow xibs
MovingSmiles
Run for iPhone and iPad, is the view blue?
Universal app so far
iPhone
iPad
Add touches
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
}
Check for double clicks
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch * anyTouch = [touches anyObject];
if (anyTouch.tapCount == 2) {
NSLog(@"Add a smile");
// Create a Smile view
}
}
UIView subclass - SmileyFace
SmileyFace.m
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
// Initialization code
self.backgroundColor = [UIColor yellowColor];
}
return self;
}
Add a Smile on double click
// Create a Smile view
CGFloat smileEdgeLength = (self.view.bounds.size.width +
self.view.bounds.size.height) / 8.0f;
SmileyFace * aSmile = [[SmileyFace alloc]
initWithFrame:CGRectMake(0, 0, smileEdgeLength,
smileEdgeLength)];
aSmile.center = [anyTouch locationInView:self.view];
[self.view addSubview:aSmile];
[aSmile release];
Yellow views on double click
iPhone
iPad
Drawing
- (void)drawRect:(CGRect)rect {
// Drawing code
// Get the context
CGContextRef context = UIGraphicsGetCurrentContext();
// Set graphics state parameters
// Add geometry to the current path
// Paint the context
CGContextDrawPath(context, kCGPathFillStroke);
}
CGContext functions
Setting Color, Color Space, and Shadow Values
Getting and Setting Graphics State Parameters
Constructing Paths - Geometry of the current path. For more CGPath Reference.
Painting Paths
Paint something
- (void)drawRect:(CGRect)rect {
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
// Set graphics state parameters
CGContextSetFillColorWithColor(context,
[UIColor redColor].CGColor);
CGContextSetStrokeColorWithColor(context,
[UIColor blackColor].CGColor);
// Add geometry to the current path
CGContextAddEllipseInRect(context,
CGRectMake(10, 10, 50, 50));
// Paint the context
CGContextDrawPath(context, kCGPathFillStroke);
}
CGContextDrawPath
CGContextDrawPath(context, kCGPathFillStroke);
void CGContextDrawPath (
CGContextRef c,
CGPathDrawingMode mode
);
enum CGPathDrawingMode {
kCGPathFill,
kCGPathEOFill,
kCGPathStroke,
kCGPathFillStroke,
kCGPathEOFillStroke
};
Red dots
iPhone
iPad
Current Transformation Matrix
These functions allow you to examine and change the current transformation matrix (CTM) in a graphics context.
Current Transformation Matrix
CGContextRef context = UIGraphicsGetCurrentContext();
CGAffineTransform ctm = CGContextGetCTM(context);
Set CTM to Identity
CGContextRef context = UIGraphicsGetCurrentContext();
CGAffineTransform ctm = CGContextGetCTM(context);
CGAffineTransform ctmInverse = CGAffineTransformInvert(ctm);
CGContextConcatCTM(context, ctmInverse);
Note: UITouch point locations would now need CGContextConvertPointToUserSpace (if needed)
CTM back to Identity
iPhone
iPad
Good habit - Push/Pop context
- (void)drawRect:(CGRect)rect {
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGAffineTransform ctm = CGContextGetCTM(context);
CGAffineTransform ctmInverse = CGAffineTransformInvert(ctm);
CGContextConcatCTM(context, ctmInverse);
...
CGContextRestoreGState(context);
}
Not actually useful here, but good practice
Start drawing a smile
- (void)drawRect:(CGRect)rect {
...
// Set graphics state parameters
CGContextSetFillColorWithColor(context, [UIColor yellowColor].CGColor);
CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);
// Add geometry to the current path
CGContextAddEllipseInRect(context, self.bounds);
...
}
Remove the backgroundColor
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
// Initialization code
self.backgroundColor = [UIColor clearColor];
}
return self;
}
Line thickness
- (void)drawRect:(CGRect)rect {
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext(); // Get the context
CGContextSaveGState(context);
CGAffineTransform ctm = CGContextGetCTM(context);
CGAffineTransform ctmInverse = CGAffineTransformInvert(ctm);
CGContextConcatCTM(context, ctmInverse);
// Set graphics state parameters
CGContextSetLineWidth(context, 4.0f);
CGContextSetFillColorWithColor(context, [UIColor yellowColor].CGColor);
CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);
// Add geometry to the current path
CGContextAddEllipseInRect(context, CGRectInset(self.bounds, 2.0f, 2.0f));
CGContextDrawPath(context, kCGPathFillStroke); // Paint the context
CGContextRestoreGState(context);
}
Yellow circles
iPhone
iPad
_eyeColor ivar
@interface SmileyFace : UIView {
UIColor * _eyeColor;
}
eyeColor property
Header File
@interface SmileyFace : UIView {
UIColor * eyeColor;
}
Implementation File
@interface SmileyFace()
@property (nonatomic, retain) UIColor * eyeColor;
@end
@implementation SmileyFace
@synthesize eyeColor = _eyeColor;
...
- (void)dealloc {
[_eyeColor release];
[super dealloc];
}
Set the eyeColor
Add the randomColor category
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
// Initialization code
self.backgroundColor = [UIColor clearColor];
self.eyeColor = [UIColor randomColor];
}
return self;
}
Drawing the eyes
- (void)drawRect:(CGRect)rect {
...
CGContextAddEllipseInRect(context, CGRectInset(self.bounds, 2.0f, 2.0f));
CGContextDrawPath(context, kCGPathFillStroke); // Paint the context
// Set graphics state parameters for the eye circles
CGContextSetLineWidth(context, 2.0f);
CGContextSetFillColorWithColor(context, self.eyeColor.CGColor);
CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);
// Add eye geometry
CGContextDrawPath(context, kCGPathFillStroke); // Paint the context
CGContextRestoreGState(context);
}
Smile geometry
45 degree angle
0.25 eye radius
0.5 distance from center
Eyes
0.7 radius
-15 degree start angle
-165 degree end angle
Smile
Handy parameters
CGFloat smileRadius = self.bounds.size.width / 2.0f - 2.0f;
CGPoint centerPoint = CGPointMake(self.bounds.size.width/2.0f,
self.bounds.size.height/2.0f);
eye geometry
// Add eye geometry
CGFloat eyeRadius = smileRadius * 0.25;
CGFloat eyeXValue = centerPoint.x +
smileRadius*0.5*cos(45.0/180.0*M_PI);
eyeXValue -= eyeRadius;
CGFloat eyeYValue = centerPoint.y +
smileRadius*0.5*sin(45.0/180.0*M_PI);
eyeYValue -= eyeRadius;
CGRect eyeRect = CGRectMake(eyeXValue, eyeYValue,
eyeRadius*2.0f, eyeRadius*2.0f);
CGContextAddEllipseInRect(context, eyeRect);
Left eye is easy (two lines)
eyeRect.origin.x -= 2.0 * (smileRadius*0.5*cos(45.0/180.0*M_PI));
CGContextAddEllipseInRect(context, eyeRect);
Eyes
iPhone
iPad
Time for the mouth
// Set graphics state parameters for the mouth
// Add eye geometry
// Paint the context
CGContextDrawPath(context, kCGPathFillStroke);
Geometry of the mouth
// Set graphics state parameters for the mouth
CGContextSetFillColorWithColor(context,
[UIColor redColor].CGColor);
// Add eye geometry
CGContextBeginPath(context);
CGContextMoveToPoint(context,
centerPoint.x+0.7f*smileRadius*cos(-165.0/180.0*M_PI),
centerPoint.y+0.7f*smileRadius*sin(-165.0/180.0*M_PI));
CGContextAddLineToPoint(context,
centerPoint.x+0.7f*smileRadius*cos(-15.0/180.0*M_PI),
centerPoint.y+0.7f*smileRadius*sin(-15.0/180.0*M_PI));
CGContextAddArc(context, centerPoint.x, centerPoint.y,
0.7*smileRadius, -15.0f/180.0*M_PI, -165.0f/180.0*M_PI, 1);
CGContextClosePath(context);
CGContextDrawPath(context, kCGPathFillStroke);
SmileyFaceWithSmile
iPhone
iPad
Getting fancy with gradients
Drawing With a Gradient
Drawing With a Shading - self investigation :)
Drawing Gradients
CGContextDrawRadialGradient(CGContextRef context,
CGGradientRef gradient,
CGPoint startCenter,
CGFloat startRadius,
CGPoint endCenter,
CGFloat endRadius,
CGGradientDrawingOptions options);
CGContextDrawLinearGradient(CGContextRef context,
CGGradientRef gradient,
CGPoint startPoint,
CGPoint endPoint,
CGGradientDrawingOptions options);
Draw linear gradient
CGContextClip(context);
CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
CGFloat gradientColorComponents[] = {0.7f, 0.7f, 0.7f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f};
CGFloat gradientLocations[] = {0.0,1.0};
CGGradientRef myGradient = CGGradientCreateWithColorComponents(rgbColorSpace,
gradientColorComponents,
gradientLocations,
2);
CGPoint gradientStartPoint = centerPoint;
CGPoint gradientEndPoint = centerPoint;
gradientStartPoint.y -= 0.1*smileRadius;
gradientEndPoint.y -= 0.7*smileRadius;
CGContextDrawLinearGradient(context, myGradient,
gradientStartPoint, gradientEndPoint,
kCGGradientDrawsAfterEndLocation | kCGGradientDrawsBeforeStartLocation);
CGColorSpaceRelease(rgbColorSpace);
CGGradientRelease(myGradient);
Saving to a CGPath
// Add mouth geometry
CGMutablePathRef mouthPath = CGPathCreateMutable();
CGPathMoveToPoint(mouthPath, &CGAffineTransformIdentity,
centerPoint.x+0.7f*smileRadius*cos(-165.0/180.0*M_PI),
centerPoint.y+0.7f*smileRadius*sin(-165.0/180.0*M_PI));
CGPathAddLineToPoint(mouthPath, &CGAffineTransformIdentity,
centerPoint.x+0.7f*smileRadius*cos(-15.0/180.0*M_PI),
centerPoint.y+0.7f*smileRadius*sin(-15.0/180.0*M_PI));
CGPathAddArc(mouthPath, &CGAffineTransformIdentity,
centerPoint.x, centerPoint.y, 0.7*smileRadius,
-15.0f/180.0*M_PI, -165.0f/180.0*M_PI, 1);
CGPathCloseSubpath(mouthPath);
Clipping path for the gradient
CGContextSaveGState(context);
CGContextAddPath(context, mouthPath);
CGContextClip(context);
Adding an stroke outline on mouth
CGContextRestoreGState(context);
CGContextAddPath(context, mouthPath);
CGContextDrawPath(context, kCGPathStroke);
Fancy smiles
iPhone
iPad
Drawing images
UIImage * someImage = [UIImage imageNamed:@"r.png"];
[someImage drawInRect:[self bounds]];
[someImage drawAtPoint:self.center];
Drawing images
Drawing text
NSString * str = @"Hello, World!";
UIFont * systemFont = [UIFont systemFontWithSize:16.0f];
[str drawInRect:[self bounds] withFont: systemFont];
[str drawAtPoint:self.center withFont: systemFont];
Drawing Strings
Drawing Strings on a Single Line
Drawing Strings in a Given Area
Want more?
Free - Watch more Matt Stroker videos from University of Utah
Book: