K线开发之CoreGraphics和CoreAnimation的比较

写在前面

关于在IOS端进行原生界面绘制,苹果开发文档里明确提供了几种方法:

  1. 使用系统提供的标准视图,例如lists, collections, alerts, images, progress bars, tables等。
  2. 使用Core Animation的图层,Core Animation不仅提供了动画的类,还提供了显示内容的图层类。
  3. 使用OpenGL ES,这个框架提供了一套开放标准的图形绘制库,主要面向游戏开发或者需要高帧速率的app。
  4. 使用UIWebView类展示基于web的图形界面。

很显然,如果你要开发一套K线框架:

  • 第一种方法肯定不适合,因为你没办法去用标准的控件来显示K线;
  • 第四种使用webview,这样的话就需要使用百度的echarts,或者还可以使用highcharts
  • 所以,想要开发原生K线,就只能选择第二种和第三种方法了
  • OpenGL ES框架使用起来比较麻烦,后续会单独在一篇文章中介绍如何使用
  • 所以,在这里,就只介绍第二种方法,也就是使用Core Animation
  • 还有一种办法,就是绕过Core Animation,直接使用Core Graphics进行绘制。这个在后面会说到。

它是什么

要使用它,就的先了解一下它是什么?

在苹果的开发文档中,有关于Core Animation的介绍,点击这儿。

这里放一张非常经典的图:

K线开发之CoreGraphics和CoreAnimation的比较_第1张图片
Core Animation

Core Animation是一个图形渲染和动画的基础库,是一个复合引擎,职责就是尽可能快地组合屏幕上不同的可视内容,这个内容是被分解成独立的图层,存储在一个叫图层树的体系之中。
Core Animation可以直接用在Max OS X和IOS平台上。
Core Animation的动画执行过程都是在后台操作的,不会阻塞主线程。
Core Animation是直接作用于CALayer,并非直接作用于UIView。
Core Animation有以下几个分类:

  • 提供显示内容的图层类
  • 动画和计时类
  • 布局和约束类
  • 事务类,在原子更新的时候组合图层类

CoreAnimation使用

在绘制k线时,主要是使用CALayer的子类CAShapeLayer,它是一个通过矢量图形而不是bitmap来绘制的图层子类。使用时,可以直接指定诸如颜色和线宽等属性,用CGPath来定义线稿绘制的图形,最后CAShapeLayer就自动渲染出来了。

首先先从最简单的开始,画一条线,代码如下:

    //初始化一个线的图层
    CAShapeLayer *lineLayer = [CAShapeLayer layer];
    //初始化一个描述的路径
    UIBezierPath *linePath = [UIBezierPath bezierPath];
    //设置线段开始的点
    [linePath moveToPoint:beginPoint];
    //设置线段结束的点
    //这里也可以添加多个点
    [linePath addLineToPoint:endPoint];
    //设置图层路径
    lineLayer.path = linePath.CGPath;
    //设置图层的其他属性
    lineLayer.lineWidth = lineWidth;
    lineLayer.strokeColor = lineColor.CGColor;
    lineLayer.fillColor = [UIColor clearColor].CGColor;

执行结果如下:

K线开发之CoreGraphics和CoreAnimation的比较_第2张图片
执行结果

从代码上可以看到,绘制线段的步骤很简单:

  1. 初始化一个图层
  2. 初始化用户线段的路径
  3. 添加线段开始的坐标点
  4. 再添加多个中间的坐标点
  5. 最后添加结束的坐标点
  6. 把路径设置到图层上去
  7. 设置图层的各个属性

其实现在再想一想K线中的分时线(如果不了解,可以点击这儿),可以直接用这段代码来绘制出来,当然,不包括分时线下方的背景颜色,并且得添加多个坐标点。

画完一条线后,再来画一个方块:

    //初始化一个rect
    CGRect frameRect = CGRectMake(x, y, width, height);
    //初始化一个图层
    CAShapeLayer *layer = [CAShapeLayer layer];
    //初始化一个描述框的路径
    UIBezierPath *path = [UIBezierPath bezierPathWithRect:frameRect];
    //把路径设置到图层中
    layer.path = path.CGPath;
    //设置图层的各个属性
    layer.strokeColor = strokeColor.CGColor;
    layer.fillColor = backColor.CGColor;

执行结果如下:

K线开发之CoreGraphics和CoreAnimation的比较_第3张图片
执行结果

绘制的步骤也很简单:

  1. 设置好框的frame
  2. 然后初始化路径的时候,直接把框的frame赋值进去
  3. 初始化一个图层
  4. 把路径设置到图层中
  5. 设置图层的各个属性

在这里,如果留心一下,其实就可以想到,框已经绘制好了,那一个蜡烛也就绘制好了,那绘制多个框,一整屏的蜡烛图不就绘制出来了。(没留心的,可以点这儿)如果你已经理解了上面所说的,那么我们在K线框架开发的道路上已经走出一大步。

Core Graphics的使用

上面有第一个地方说到,绘制界面除了使用Core Animation以外,还可以绕过Core Animation直接使用OpenGL ES或者Core Graphics。

在这里,介绍一下Core Graphics。Core Graphics是一套基于C的API框架,使用了Quartz作为绘图引擎。它提供了低级别、轻量级、高保真度的2D渲染。该框架可以用于基于路径的绘图、变换、颜色管理、脱屏渲染,模板、渐变、遮蔽、图像数据管理、图像的创建、遮罩以及PDF文档的创建、显示和分析。

和上面一样,也是从最基础的一条线开始:

    //获取当前上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //开始记录路径
    CGContextBeginPath(ctx);
    //设置开始坐标点
    CGContextMoveToPoint(ctx, beginPoint);
    //添加坐标点,或者也可以只添加一个坐标点
    CGContextAddLineToPoint(ctx, endPoint);
    //结束记录路径
    CGContextClosePath(ctx);
    //设置线段宽度
    CGContextSetLineWidth(ctx, lineWidth);
    //设置颜色
    CGContextSetStrokeColorWithColor(ctx, lineColor.CGColor);
    //开始绘制路径
    CGContextStrokePath(ctx);

执行效果和上面使用CAShapeLayer绘制线段的效果一样。

依次类推,可以绘制一条线,也就可以绘制一个框。

这里说明一下,代码中的CGContext 上下文定义了绘制的地方。在使用UIKit时,上下文是唯一的,UIKit会维护着一个上下文堆栈,而UIKit方法总是绘制到最顶层的上下文中。

一般使用Core Graphics进行绘制,都会重写drawRect方法,所以这里的上下文就是上下文堆栈最顶层的上下文,使用UIGraphicsGetCurrentContext就可以获取到。

两者比较

这里总结一下,上述介绍了两种绘制图形的方式:

  1. 使用Core Animation的 CAShapeLayer图层子类
  2. 使用Core Graphics

那两种方式有什么区别呢?

  1. CAShapeLayer渲染更快速。因为它使用了硬件加速,绘制同一图形会比用Core Graphics快很多。
  2. CAShapeLayer更高效使用内存。一个CAShapeLayer不需要像普通CALayer一样创建一个寄宿图形,所以无论有多大,都不会占用太多的内存。
  3. CAShapeLayer不会被图层边界剪裁掉,一个 CAShapeLayer 可以在边界之外绘制。你的图层路径不会像在使用 Core Graphics 的普通 CALayer 一样被剪裁掉。
  4. CAShapeLayer不会出现像素化。当你给 CAShapeLayer 做3D变换时,它不像一个有寄宿图的普通图层一样变得像素化。

其实最后一点最关键,因为它正好符合了k线框架开发的业务需求,一语中的。

一旦你实现了 CALayerDelegate 协议中的 -drawLayer:inContext: 方法或者 UIView 中的 -drawRect: 方法(其实就是前者的包装方法),图层就创建了一个绘制上下文,这个上下文需要的内存可从这个公式得出:图层宽x图层高x4字节,宽高的单位均为像素。对于一个在 Retina iPad 上的全屏图层来说,这个内存量就是 2048x1526x4字节,相当于12MB内存,图层每次重绘的时候都需要重新抹掉内存然后重新分配。

而当我们使用k线的时候,左滑或者右滑时,都会触发重新绘制,而每次重绘时都会重新获取一个绘制上下文。而左滑或者右滑时,会高频率的进行重绘,所以避免不了内存的重新分配。

当然,这里也不是说Core Graphics效率就很差,只是恰好在这样的业务需求下,会把某一个问题放大。并且,不要忘了CAShapeLayer绘制的图形是直接操作layer,不会作用于UIView,更不会去响应用户的交互。

你可能感兴趣的:(K线开发之CoreGraphics和CoreAnimation的比较)