在iOS中实现自定义绘图,需要获得一个graphics context对象,它就是你画图的地方(可以理解为一张画板)。总的来说你有两种方法来获得它:

1.如何得到一个画板(Context)

下面详细说一下:

a.自己创建

通过UIGraphicsBeginImageContextWithOptions方法就可以获得一个图形上下文,然后你就可以在其上进行绘图操作,当绘图操作完成以后,可以通过UIGraphicsGetImageFromCurrentImageContext 得到一个代表绘制内容的UIImage对象,最后不要忘了调用UIGraphicsEndImageContext关闭此图形上下文。

步骤大概这样:

  1. 通过 UIGraphicsBeginImageContextWithOptions 创建context
  2. 执行绘制操作(UIBezierPath/Core Graphics)
  3. 通过 UIGraphicsGetImageFromCurrentImageContext 得到UIImage对象
  4. 通过 UIGraphicsEndImageContext 关闭context

示例代码:

1
2
3
4
5
UIGraphicsBeginImageContextWithOptions(CGSizeMake(100, 100), false, 0)
//do some draw ...
let image = UIGraphicsGetImageFromCurrentImageContext()
//to do something with the image object
UIGraphicsEndImageContext()

b. Cocoa提供

  • 自定义UIView,重写 drawRect: 方法,此方法中已由Cocoa设置好了Context
  • 自定义UIView,重写 drawLayer:inContext: 第二个参数就是一个Context

(以上两种方式任选一种)

示例代码:

1
2
3
4
5
6
7
8
9
10
class CustomView: UIView {

override func drawRect(rect: CGRect) {
//just draw ...
}

override func drawLayer(layer: CALayer, inContext ctx: CGContext) {
//draw something whit ctx ...
}
}

两种方式的对比

  1. 通过 UIGraphicsBeginImageContextWithOptions 创建的context会被自动设置为当前环境的context,所以这种方式下执行绘图时可以直接使用UIKit的绘图方法,不需要进行额外的操作(UIKit只能基于当前Context绘制)
  2. drawRect 方法中已自动设置好了context可以直接进行UIKit方式的绘图
  3. drawLayer 方法中的context,并没有被自动设置为当前环境的context,所以不能直接进行UIKit方式的绘制

2. 两种绘图框架

iOS支持两套绘图API: Core Graphics/QuartZ 2DOpenGL ES. 前者又可以被细分为两种: UIKit方式Core Graphics方式,其实所谓UIKit方式也是基于Core Graphics的,它只是对Core Graphics的一个面向对象的封装(Core Graphics是一套基于C的面向过程的绘图API).
OpenGL ES是一套跨平台的图形API接口,它只是定义了一套API接口,实现由各个厂商自己做,做iOS的应用开发一般使用不到这种方式,所以这种方式的绘图不在今天的讨论范围.下面详细讨论一下UIKitCore Graphics方式.

a. UIKit

这种方式就是对Core Graphics方式的一种简化封装,你可以用面向对象的方式很方便的做各种绘图操作,主要是通过UIBezierPath这个类来实现的, UIBezierPath可以创建基于矢量的路径,例如各种直线,曲线,圆等等
使用这种方式绘图你的代码看上去,大概是这样:

1
2
3
4
let p = UIBezierPath(ovalInRect: CGRectMake(0,0, 100, 100))
UIColor.blueColor().setFill()
p.fill()
// ...

b. Core Graphics

这种方式使用起来要比UIKit方式复杂一些,它是面向过程的,它的每一个绘图函数都需要传入一个context对象,如果你当前位于UIGraphicsBeginImageContextWithOptions函数或drawRect:方法中,并没有引用一个上下文。为了使用Core Graphics,你可以调用UIGraphicsGetCurrentContext函数获得当前的图形上下文。
使用这种方式绘图你的代码看上去,大概是这样:

1
2
3
4
5
let ctx = UIGraphicsGetCurrentContext()!
CGContextAddEllipseInRect(ctx, CGRectMake(0, 0, 100, 100))
CGContextSetFillColorWithColor(ctx, UIColor.blueColor().CGColor)
CGContextFillPath(ctx)
// ...

两种方式的对比

  1. UIKit也是基于Core Graphics的,是对Core Graphics的一种封装,使用起来更简便, Core Graphics的功能更强大但也更复杂.
  2. UIKit只能基于当前Context绘制,可以通过UIGraphicsGetCurrentContext函数获得当前的图形上下文。

3. 六种绘图形式

至此,我们有了两大绘图框架的支持以及三种获得图形上下文的方法(drawRect:、drawRect: inContext:、UIGraphicsBeginImageContextWithOptions)。那么我们就有6种绘图的形式:

1 . 在UIView的子类方法drawRect:中绘制一个蓝色圆, 使用 UIKit方式:

1
2
3
4
5
override func drawRect(rect: CGRect) {
let p = UIBezierPath(ovalInRect: CGRectMake(0, 0, 100, 100))
UIColor.blueColor().setFill()
p.fill()
}

2 . 在UIView的子类方法drawRect:中绘制一个蓝色圆, 使用 Core Graphics方式:

1
2
3
4
5
6
override func drawRect(rect: CGRect) {
let con = UIGraphicsGetCurrentContext()!
CGContextAddEllipseInRect(con, CGRectMake(0, 0, 100, 100))
CGContextSetFillColorWithColor(con, UIColor.blueColor().CGColor)
CGContextFillPath(con)
}

3 . 在UIView子类的drawLayer:inContext:方法中,使用UIKit方式:

1
2
3
4
5
6
7
override func drawLayer(layer: CALayer, inContext ctx: CGContext) {
UIGraphicsPushContext(ctx) //将ctx设置为当前context
let p = UIBezierPath(ovalInRect: CGRectMake(0, 0, 100, 100))
UIColor.blueColor().setFill()
p.fill()
UIGraphicsPushContext(ctx)
}

4 . 在UIView子类的drawLayer:inContext:方法中,使用Core Graphics方式:

1
2
3
4
5
override func drawLayer(layer: CALayer, inContext ctx: CGContext) {
CGContextAddEllipseInRect(ctx, CGRectMake(0, 0, 100, 100))
CGContextSetFillColorWithColor(ctx, UIColor.blueColor().CGColor)
CGContextFillPath(ctx)
}

5 . 使用UIGraphicsBeginImageContextWithOptions创建画板&用UIKit方式绘制:

1
2
3
4
5
6
7
UIGraphicsBeginImageContextWithOptions(CGSizeMake(100, 100), false, 0)
let p = UIBezierPath(ovalInRect: CGRectMake(0, 0, 100, 100))
UIColor.blueColor().setFill()
p.fill()
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
//to do something with the image

6 . 使用UIGraphicsBeginImageContextWithOptions创建画板&用Core Graphics方式绘制:

1
2
3
4
5
6
7
UIGraphicsBeginImageContextWithOptions(CGSizeMake(100, 100), false, 0)
let con = UIGraphicsGetCurrentContext()
CGContextAddEllipseInRect(con, CGRectMake(0, 0, 100, 100))
CGContextSetFillColorWithColor(con, UIColor.redColor().CGColor)
CGContextFillPath(con)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

参考

http://www.cocoachina.com/industry/20140115/7703.html

版权声明

文章版权归本人所有,如需转载需在明显位置处保留作者信息及原文链接 !