下面的笑脸这就是今天我们要画的图 。
我们应该如何使用iPhone进行绘图,iPhone的绘图是在UIVIew的drawRect方法中实现的。如果我们要在UIView绘制图呢,就要写一个UIVIew的扩展类,并重写drawRect方法。那么程序执行的时候,会调用此方法进行绘制。
比如,现在我们要绘制一个笑脸,在 drawRect 实现的代码如下,我将整个文件代码都贴上:
FaceView.h
//
// FaceView.h
// Happiness
//
// Created by surfboy on 1/30/13.
// Copyright (c) 2013 SurfBoy. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface FaceView : UIView
@end
FaceView.m
//
// FaceView.m
// Happiness
//
// Created by surfboy on 1/30/13.
// Copyright (c) 2013 SurfBoy. All rights reserved.
//
#import "FaceView.h"
@implementation FaceView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setup];
}
return self;
}
- (void)awakeFromNib {
[self setup];
}
- (void)setup {
self.contentMode = UIViewContentModeRedraw;
}
// 画圆
- (void)drawCircleAtPoint:(CGPoint)p withRadius:(CGFloat)radius inContext:(CGContextRef)context {
// UIGraphicsPushContext UIGraphicsPopContext 保证不破坏调用程序的Context
UIGraphicsPushContext(context);
// 创建一个路径
CGContextBeginPath(context);
// 调用画圆的方法
CGContextAddArc(context, p.x, p.y, radius, 0, 2*M_PI, YES);
// 开始画路径
CGContextStrokePath(context);
// 弹出当前的Context
UIGraphicsPopContext();
}
#define DEFAULT_SCALE 0.9
#define DEFAULT_EYE_RADIUS 0.1
#define DEFAULT_EYE_H 0.35
#define DEFAULT_EYE_V 0.35
#define DEFAULT_MOUTH_H 0.45
#define DEFAULT_MOUTH_V 0.45
#define DEFAULT_MOUTH_SMILE 0.3
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// 取得当前上下文
CGContextRef context = UIGraphicsGetCurrentContext();
// 计算出屏幕中心的点x,y
CGPoint midPoint;
midPoint.x = self.bounds.origin.x + self.bounds.size.width / 2;
midPoint.y = self.bounds.origin.y + self.bounds.size.height /2;
// 计算出圆的半径,为了留点边距 * DEFAULT_SCALE
CGFloat size = self.bounds.size.width /2;
// 旋转屏幕的时高与宽对调
if (self.bounds.size.height < self.bounds.size.width) size = self.bounds.size.height / 2;
// 按比例缩小,留出边距
size *= DEFAULT_SCALE;
// 设置线的宽
CGContextSetLineWidth(context, 5.0);
// 颜色
[[UIColor blueColor] setStroke];
// 开始画圆
[self drawCircleAtPoint:midPoint withRadius:size inContext:context];
// *开始画第一只眼睛,定位主要靠midPoint为基点
CGPoint eyePoint;
eyePoint.x = midPoint.x - size * DEFAULT_EYE_H;
eyePoint.y = midPoint.y - size * DEFAULT_EYE_V;
[self drawCircleAtPoint:eyePoint withRadius:size * DEFAULT_EYE_RADIUS inContext:context];
// 第二只眼睛
eyePoint.x += size * DEFAULT_EYE_H * 2;
[self drawCircleAtPoint:eyePoint withRadius:size * DEFAULT_EYE_RADIUS inContext:context];
// *开始画嘴,定义第一个点 // http://www.xushao.net/2013/01/31/3944
CGPoint mouthStart;
mouthStart.x = midPoint.x - size * DEFAULT_MOUTH_H;
mouthStart.y = midPoint.y + size * DEFAULT_MOUTH_V;
// 结速的点
CGPoint mouthEnd = mouthStart;
mouthEnd.x += DEFAULT_MOUTH_V * size * 2;
// Curve Point1
CGPoint mouthCP1 = mouthStart;
mouthCP1.x += DEFAULT_MOUTH_H *size * 2 / 3;
// Curve Point2
CGPoint mouthCP2 = mouthEnd;
mouthCP2.x -= DEFAULT_MOUTH_H * size * 2 / 3;
// 笑容指数
float smile = 1;
// DEFAULT_MOUTH_SMILE 越高,笑得越开
CGFloat smileOffset = DEFAULT_MOUTH_SMILE * size * smile;
mouthCP1.y += smileOffset;
mouthCP2.y += smileOffset;
CGContextBeginPath(context);
CGContextMoveToPoint(context, mouthStart.x, mouthStart.y);
CGContextAddCurveToPoint(context, mouthCP1.x, mouthCP1.y, mouthCP2.x, mouthCP2.y, mouthEnd.x, mouthEnd.y);
CGContextStrokePath(context);
}
@end
以上的代码,我都做了一个详细的注解说明,至于调用方法的详细参数说明和用法请查看官网文档,它已经写得很清楚了。
说明一下,绘制和重绘都是在drawRect中完成,但我们一般不直接调用 drawRect,苹果也不建议我们这么干。苹果要求我们使用 UIView 中的 setNeedsDisplay方法,这个方法程序会自动调用drawRect进行绘制。
上面的代码,主要的思路很简单。计算出中心点 midPoint ,size *DEFAULT_SCALE 是为了圆与屏幕保留一定的距离。然后下面的眼、嘴都是按照midPoint、size为基数进行计算。稍微有点难理解的就是画嘴,因为它可以笑也可以不开心,不明白的可以看注解的地址,很清析说明。
在我们旋转设备的时候,你会发现,表情图不会重绘?而是被拉长了。只要我们设置 self.contentMode = UIViewContentModeRedraw; 当设置或者iframe发生改变的时候,都会自动调用 drawRect。我新建了一个方法setup,然后分别在 awakeFromNib、initWithFrame 调用。