美文网首页iOS开发实践iOS技术博客·BlogiOS学习开发
iOS实现自定义绘图的几种方式(Swift版)

iOS实现自定义绘图的几种方式(Swift版)

作者: 201e7f3210f4 | 来源:发表于2016-05-07 14:39 被阅读4622次

    本文首发在我的个人博客ghui.me 欢迎指教

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

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

    a.自己创建

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

    步骤大概这样:

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

    示例代码:

    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

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

    示例代码:

    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可以创建基于矢量的路径,例如各种直线,曲线,圆等等
    使用这种方式绘图你的代码看上去,大概是这样:

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

    b. Core Graphics

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

    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方式:

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

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

    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方式:

    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方式:

    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方式绘制:

    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方式绘制:

    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

    个人微信公众号已开通:CoderGhui ,欢迎关注!

    相关文章

      网友评论

      本文标题:iOS实现自定义绘图的几种方式(Swift版)

      本文链接:https://www.haomeiwen.com/subject/ietsrttx.html