玩转iOS中的绘图(Quartz 2D基础篇)

作者: ZeroJ | 来源:发表于2016-06-07 17:29 被阅读1671次
前言: 本篇简单介绍使用Quartzs 2D来绘图.如果你在网上搜索关于iOS开发中对于图片的处理(缩放...),或者运用截取屏幕或者某一部分内容来实现一些动画交互(比如实现tableViewCell, collectionView的移动效果...), 以及自定义一些控件(比如圆形进度条...)那么大多数的处理都会涉及到绘图的处理, 也许很多功能在你需要实现的时候, 搜索一下可以找到一些解决问题的代码, 但是或许在使用很久之后还是不明白其中的知识点. 本篇大多内容源于对官方文档"Quartz 2D Programming Guide"的理解.

首先对于Quartz 2D就不多做介绍了,(处理路径的绘图, 透明度绘图, 遮盖,阴影, 颜色管理, 防锯齿渲染, 生成PDF...) 感兴趣的朋友可以查查相关的资料

1. 了解Quartz 2D的绘图机制

  • 和现实中的绘图一样, 首先需要一张"画布", 在iOS中被称为 "图形上下文", 这个图形上下文包含了设备的信息等很多系统准备好的内容
  • 在上下文中运用一些方法来设置我们要绘制的内容和属性,来实现绘图
  • Quartz 2D类似打印机, 对不同的内容的绘图顺序不同, 得到的结果就不相同
    这里有一张官方的图的解释,很直接


    painters_model.gif

2.获取上下文

  • 重写UIView的drawRect()方法, 当这个view的内容需要更新的时候会调用这个方法, 所以系统在这个方法里面会默认提供一个上下文, 可以通过UIGraphicsGetCurrentContext() 获取到
  • 在其他地方可以通过UIGraphicsBeginImageContextWithOptions()开启一个上下文, 然后通过 UIGraphicsGetCurrentContext() 可以获取到
  • 关于drawRect()方法(处理不当时有人称为"内存恶魔")
    // 调用setNeedsDisplay()这个函数会触发drawRect方法, 当这个函数被调用的时候, 系统会通知这个UIView整个界面需要重绘. 但是这个函数会直接返回, 但界面的变化不会马上返回, 需要等到下个生命周期进行重绘
    // 如果只有一部分需要重绘 可以调用这个方法 setNeedsDisplayInRect(rect: CGRect)
    // 这个方法里面应该只做与界面的绘制有关的工作, 不应该进行任何的数据处理或者程序的逻辑相关的任务, 以保证尽快执行完毕

3. 坐标系

  • 和数学中的直角坐标系相同, 原点在左下角, UIKit中的坐标系的原点在左上角, 所以使用Quartz 2D绘图的时候要注意进行坐标系的转换

4. 内存管理

  • 因为使用的C语言的东西, 编译器并没有给我们自动管理内存, 在oc中需要我们自己来管理, 即当调用含有create或者copy的函数获得上下文的时候, 需要在使用完后手动release, 但在swift中我们不用管理了(而且C语言的函数在swift中看上去也比较习惯)

5. 绘制我们需要的内容

  • 5.1 绘制路径

    • 首先需要我们画出路径 -> 指定起始点到另一个点, 然后两点之间可以使用直线或者曲线来连接, 就形成了一条路径, 例如使用下面的函数来实现
    ```
    

    CGContextMoveToPoint() -> 指定起始点或者移动到新的点
    CGContextAddLineToPoint() -> 从当前的点到指定的点之间画一条线
    CGContextAddArc() -> 圆弧
    CGContextAddArcToPoint() -> 会在当前点和指定点与坐标系平行的直线做切线画圆弧
    CGContextAddCurveToPoint() -> 画曲线(bezier)
    CGContextClosePath() -> 将起始点和结束点连接起来形成封闭的路径
    CGContextAddEllipseInRect() -> 椭圆
    ```

    • 然后设置需要绘制的路径的属性 -> 设置颜色,透明度,宽度, 绘制模式...例如使用如下的函数来实现
    ```
    

CGContextSetLineWidth() -> 线宽度
CGContextSetLineJoin() -> 线的连接点的样式
CGContextSetLineCap() -> 端点的样式
CGContextSetLineDash() -> 虚线
CGContextSetStrokeColorWithColor() -> stroke模式时的颜色
CGContextSetFillColorWithColor() -> fill模式时的颜色
```
* 绘制内容, 注意会涉及到两种方式: fill 和 stroke, 这里解释一下两者的区别

  • 当使用stroke方式 -> "描边"即只绘制路径
  • 当使用fill方式"填充"即绘制路径包括的所有区域(所有路径都会被当作closePath处理)

  • Filling有两种模式
    nonzero winding number(默认) -> 如果两个路径有重叠的时候, 绘制方向相同的话, 那么重叠部分的绘制可能不是我们希望的
    even-odd -> 不受绘制方向的影响
    CGContextEOFillPath
    CGContextFillPath
    CGContextFillRect
    CGContextFillRects
    CGContextFillEllipseInRect

      CGContextStrokePath(context)
      CGContextFillPath(context)
    
    
  • 示例
    stroke模式绘制线

```
override func drawRect(rect: CGRect) {
    // Drawing code
    // 获取当前上下文
    let context = UIGraphicsGetCurrentContext()
    let strokeColor = UIColor.blueColor()
    // 设置stroke模式的颜色使用CGColor(这里涉及到颜色和颜色空间的概念)
    CGContextSetStrokeColorWithColor(context, strokeColor.CGColor)
    // 设置线的宽度
    CGContextSetLineWidth(context, 5.0)
    // 设置连接处样式...还可以设置很多其他的属性
    CGContextSetLineJoin(context, CGLineJoin.Round)
    // 起始点
    CGContextMoveToPoint(context, 10.0, 10.0)
    // 在点(10.0, 10.0)和(10.0, 80.0)之间画一条线 所以点(10.0, 80.0)被设置为下一个起始点
    CGContextAddLineToPoint(context, 10.0, 80.0)
    //在点(10.0, 80.0)和(80.0, 80.0)之间画一条线 所以点(80.0, 80.0)被设置为下一个起始点
    CGContextAddLineToPoint(context, 80.0, 80.0)
    // 设置为封闭路径, 会将首尾点连接起来
    // CGContextClosePath(context)
    // 绘制当前的路径
    CGContextStrokePath(context)
    
}

```
不封闭路径png 封闭路径.png

fill模式绘制相同的路径

     let fillColor = UIColor.blueColor()
     // 设置fill模式的颜色使用CGColor(这里涉及到颜色和颜色空间的概念)
     CGContextSetFillColorWithColor(context, fillColor.CGColor)
     // 起始点
     CGContextMoveToPoint(context, 10.0, 10.0)
     // 在点(10.0, 10.0)和(10.0, 80.0)之间画一条线 所以点(10.0, 80.0)被设置为下一个起始点
     CGContextAddLineToPoint(context, 10.0, 80.0)
     //在点(10.0, 80.0)和(80.0, 80.0)之间画一条线 所以点(80.0, 80.0)被设置为下一个起始点
     CGContextAddLineToPoint(context, 80.0, 80.0)
     //        CGContextClosePath(context)
     // 绘制当前的路径
     CGContextFillPath(context)
   ```

![fill方式.png](http:https://img.haomeiwen.com/i1271831/3729cb7a3c50b757.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

stroke模式绘制圆

    // 设置stroke模式的颜色使用CGColor(这里涉及到颜色和颜色空间的概念)
    CGContextSetStrokeColorWithColor(context, strokeColor.CGColor)
    // 设置线的宽度
    CGContextSetLineWidth(context, 5.0)
    // 设置连接处样式
    CGContextSetLineJoin(context, CGLineJoin.Round)
    // 起始点
    let circleCenter = CGPoint(x: rect.width * 0.5, y: rect.height * 0.5)
    CGContextMoveToPoint(context, circleCenter.x*2, circleCenter.y)
    // 画圆
    // x -> 圆心的x坐标
    // y -> 圆心的y坐标
    // radius -> 圆的半径
    // startAngle -> 起始角度 (弧度制) 所以上面调整了起始点
    // endAngle -> 结束角度(弧度制)
    CGContextAddArc(context, circleCenter.x, circleCenter.y, rect.width * 0.5, 0.0, CGFloat(M_PI) * 2, 0)
    CGContextStrokePath(context)

![stroke圆png](http:https://img.haomeiwen.com/i1271831/80e1a3a80711373c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

fill方式绘制圆

    // 设置fill模式的颜色使用CGColor(这里涉及到颜色和颜色空间的概念)
    CGContextSetFillColorWithColor(context, fillColor.CGColor)
    // 起始点
    let circleCenter = CGPoint(x: rect.width * 0.5, y: rect.height * 0.5)
    CGContextMoveToPoint(context, circleCenter.x*2, circleCenter.y)
    // 画圆
    // x -> 圆心的x坐标
    // y -> 圆心的y坐标
    // radius -> 圆的半径
    // startAngle -> 起始角度 (弧度制) 所以上面调整了起始点
    // endAngle -> 结束角度(弧度制)
    CGContextAddArc(context, circleCenter.x, circleCenter.y, rect.width * 0.5, 0.0, CGFloat(M_PI) * 2, 0)
    // 绘制当前的路径
    CGContextFillPath(context)

![fill方式.png](http:https://img.haomeiwen.com/i1271831/da58c13499f817c6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

-----
#####仅仅介绍了上面的几种看上去很简单的绘制方法, 也许你会觉得没有什么实际用处, 但是实际上是很有用处的, 因为到现在为止, 你可以使用Quartzs 2D来实现自定义的各种圆形进度条了,(可能使用到stroke和fill的混合模式), 只需要在提供的progress属性设置时调用setNeedsDisplay()就可以触发drawRect()方法进行重绘, 而在这里面你就可以利用progress来改变绘制的内容了, 从而实现进度条的效果
---
> 限于篇幅和时间, 这篇中只是梳理了一些基本的绘图概念和绘制简单的图形(实际上看看API就可以类似的使用相关的方法绘制出其他的图形 -- 椭圆...), 而实际上还有比较多的东西需要研究, 以后有必要在补上. [Demo](https://github.com/jasnig/DrawingStudy)

相关文章

  • iOS-绘图Quartz 2D 贝赛尔曲线相关

    本篇涵盖iOS中绘图上下文,截屏相关等. 1.玩转iOS中的绘图(Quartz 2D基础篇)2.分享iOS中常用的...

  • 绘图

    IOS中绘图的方式介绍 IOS中貌似绘图的方式还挺多的,有 Core Graphics/QuartZ 2D UIK...

  • 玩转iOS中的绘图(Quartz 2D基础篇)

    前言: 本篇简单介绍使用Quartzs 2D来绘图.如果你在网上搜索关于iOS开发中对于图片的处理(缩放...),...

  • Quartz 2D

    Quartz 2D简介 Quartz 2D是一个二维绘图引擎,同时支持iOS和Mac系统 Quartz 2D能完成...

  • Quartz 2D 绘图技术

    Quartz 2D。是 iOS 和 Mac OS X 环境下的2D绘图引擎。Quartz 2D 也被称为 Core...

  • Quartz2D

    Quartz2D Quartz 2D是一个二维绘图引擎,同时支持iOS和Mac系统 Quartz2D在iOS开发中...

  • Quartz 2D 在 swift 中的使用

    Quartz 2D是一个二维绘图引擎,同时支持iOS和Mac系统。其实 iOS 中很多控件都是通过 Quartz ...

  • Quartz 2D绘图 (1)初识

    Quartz 2D介绍 什么是Quartz2D ?Quartz 2D是⼀个二维绘图引擎,同时支持iOS和Mac系统...

  • Quartz2D简单介绍

    一、什么是Quartz2D Quartz 2D是⼀个二维绘图引擎,同时支持iOS和Mac系统 Quartz 2D能...

  • iOS 绘图学习笔记 - (1)绘图的基本内容

    iOS中能够用来绘图的框架一般是 UIKit , Quartz 2D(CoreGraphic), OpenGL, ...

网友评论

本文标题:玩转iOS中的绘图(Quartz 2D基础篇)

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