zoukankan      html  css  js  c++  java
  • Quartz2D 备忘 + 学习

    Quartz2D 

    Quartz2D是支持iOS和Mac系统的二维绘制引擎,它可以绘制:

    • 绘制图形(图形,线条,圆等)
    • 绘制文字
    • 绘制/生成图片
    • 读取/生成PDF
    • 截图

    Quartz2D主要功能就是以画为主,它可以实现与用户交互的画板或实现UIKit框架中不好展示的一些图形 如:饼图,柱状图。在自定义控件的时候也可以绘制控件,iOS中大部分控件都是用Quartz2D绘制出来的。

    图形上下文

    图形上下文说白了就是画布,没有图形上下文就不能绘制任何图形,Quartz2D 提供了五种图形上下文,不同的图形上下文决定画出的内容将展示在不同的情况中。

    • Bitmap Graphics Context:位图上下文,在这个上下文中绘制的内容可以获取成图片。(这个上下文只能主动创建来使用,使用完毕后要销毁)。
    • PDF Graphics Context:PDF上下文,用于生成绘制PDF文件。
    • Window Graphics Context:
    • Layer Graphics Context:图层上下文,一般用于绘制UI控件使用。
    • Printer Graphics Context:

    drawRect方法

    一般我们最常用的就是绘制一些自定义控件,那么如何获得相应上下文呢?答案是:在drawRect方法中获取,一般获取到的是Layer Graphics Context(图层上下文),获取到上下文后就可以绘制一些我们想要的内容了,需要注意的是我们绘制的内容全部在view内部的layer上。

    class CustomView: UIView {
        override func drawRect(rect: CGRect) {
            // 获取当前的上下文
            let contextRef = UIGraphicsGetCurrentContext()
        }
    }
    

     那么这个方法什么时候被调用?请看以下几种情况:

    当view第一次显示在屏幕上时。

    改变某个属性让view必须重绘时(比如改变背景色,添加子view时)。

    当我们主动调用setNeedsDisplay或setNeedsDisplayInRect方法时drawRect会被调用,注意:我们主动调用drawRect方法是无效的。

    绘制一条简单的线

    class CustomView: UIView {
        override func drawRect(rect: CGRect) {
            // 获取当前的上下文
            let contextRef = UIGraphicsGetCurrentContext()
            CGContextMoveToPoint(contextRef, 0, 0)
            CGContextAddLineToPoint(contextRef, 50, 50)
            CGContextSetLineWidth(contextRef, 20)
            UIColor.yellowColor().set()
            CGContextStrokePath(contextRef)
        }
    }
    

     下面我们来看下常用的绘制函数(更多属性参考官方文档):

    • UIGraphicsGetCurrentContext():获取当前的上下文,一般在drawRect方法中才能获得。
    • CGContextMoveToPoint(contextRef, 50, 0.0):新建一个起点。
    • CGContextAddLineToPoint(contextRef, 50, 50):新添加一条线到新的点。
    • CGContextAddLines(contextRef, [CGPointMake(10.0, 10.0), CGPointMake(50.0, 50.0), CGPointMake(20.0, 80.0)], 3):添加若干条线
    • CGContextAddRect(contextRef, CGRectMake(10, 10, 20, 20)):添加一个矩形。
    • CGContextAddEllipseInRect(contextRef, CGRectMake(10, 10, 60, 60)):添加一个椭圆。
    • CGContextAddArc(contextRef, 40, 40, 20, 0.0, CGFloat(M_PI), 0):添加一条圆弧,解释下几个参数:1图层上下文,2圆心的X点,3圆心的Y点,4半径长度,5起始角度,6结束角度,7是否是顺时针 1为顺时针 0为逆时针。
    • CGContextAddArcToPoint(contextRef, 40.0, 40.0, 70.0, 80.0, 30.0):添加一条曲线。
    • CGContextClosePath(contextRef):将没有结合的两个点封起来。
    • CGContextDrawPath(contextRef, .FillStroke):绘制图形,并且设置填充模式。
    • CGContextStrokePath(contextRef):绘制图形,只是绘制不会有填充封闭效果。
    • CGContextFillPath(contextRef):绘制图形,会有填充封闭效果。
    • CGContextRotateCTM(contextRef, CGFloat(M_PI_4)):矩阵旋转。
    • CGContextScaleCTM(contextRef, 1.0, 0.5):矩阵缩放。
    • CGContextTranslateCTM(contextRef, 10, 10):矩阵平移。

    上下文栈

    先来看两个方法:

    • CGContextSaveGState(contextRef):将当前的上下文copy一份,保存到上下文栈的栈顶。
    • CGContextRestoreGState(contextRef):将上下文栈栈顶重置。

    那么上下文栈有什么用呢?下面来看一个比较繁琐的例子:

        override func drawRect(rect: CGRect) {
            // 获取当前的上下文
            let contextRef = UIGraphicsGetCurrentContext()
            
            // 设置上下文的状态
            CGContextSetLineWidth(contextRef, 3.0)
            CGContextSetLineCap(contextRef, .Round)
            UIColor.redColor().set()
            
            // 绘制第一条线
            CGContextMoveToPoint(contextRef, 0.0, 0.0)
            CGContextAddLineToPoint(contextRef, 30.0, 30.0)
            
            // 绘制
            CGContextStrokePath(contextRef)
            
            // 重置属性
            CGContextSetLineCap(contextRef, .Square)
            CGContextSetLineWidth(contextRef, 1.0)
            UIColor.blackColor().set()
            
            // 绘制第二条线
            CGContextMoveToPoint(contextRef, 10.0, 50.0)
            CGContextAddLineToPoint(contextRef, 80.0, 80.0)
            // 绘制
            CGContextStrokePath(contextRef)
        }
    

      分析:

    1. 我们绘制第一条线之前把上下文的属性做了设置,之后绘制。
    2. 如果第二条线不想与第一条线一样,做了属性的再一次设置成默认的样式,然后绘制。

    注意:虽然这样也可以达成效果,but 如果在实际开发中会大大增加代码量,最好的办法是重置栈顶的上下文。

    看一个正确做法的例子:

        override func drawRect(rect: CGRect) {
            // 获取当前的上下文
            let contextRef = UIGraphicsGetCurrentContext()
            
            // 1、copy上下文至栈顶
            CGContextSaveGState(contextRef)
            
            // 设置状态 再次copy
            CGContextSetLineWidth(contextRef, 3.0)
            CGContextSaveGState(contextRef)
            
            // 设置上下文的状态
            CGContextSetLineCap(contextRef, .Round)
            UIColor.redColor().set()
            
            // 绘制第一条线
            CGContextMoveToPoint(contextRef, 0.0, 0.0)
            CGContextAddLineToPoint(contextRef, 30.0, 30.0)
            CGContextStrokePath(contextRef)
            
            // 2、将栈顶出栈,重置当前的上下文
            CGContextRestoreGState(contextRef)
            
            // 绘制第二条线
            CGContextMoveToPoint(contextRef, 10.0, 50.0)
            CGContextAddLineToPoint(contextRef, 80.0, 80.0)
            CGContextStrokePath(contextRef)
            
            // 3、再次出栈
            CGContextRestoreGState(contextRef)
            
            // 绘制第三条线
            CGContextMoveToPoint(contextRef, 40.0, 40.0)
            CGContextAddLineToPoint(contextRef, 90.0, 70.0)
            CGContextStrokePath(contextRef)
        }
    
    • 第一条线:圆角,颜色为红色,宽度为3
    • 第二条线:当绘制完第一条线完毕后做了一次出栈,第二条线样式为 宽度为3 其他默认。
    • 第三条线:当绘制完第二条线后又做了一次出栈,第三条线为默认样式。
  • 相关阅读:
    天下没有不会这么回事!不会就学——北漂18年(28)
    Python Module_sys/random
    Python Module_sys/random
    redis 主从切换
    第一章 数据引用与匿名存储
    第12章 对象上
    zabbix 发送邮件配置
    第10章 包 名字空间,变量和函数
    perl 类 对象 方法
    perl数据结构输出 Data::Dumper
  • 原文地址:https://www.cnblogs.com/Alex-sk/p/5581271.html
Copyright © 2011-2022 走看看