美文网首页
K线开发之CoreGraphics和CoreAnimation的

K线开发之CoreGraphics和CoreAnimation的

作者: nethanhan | 来源:发表于2017-10-14 13:36 被阅读0次

    写在前面

    关于在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的介绍,点击这儿

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

    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;
    

    执行结果如下:

    执行结果

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

    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;
    

    执行结果如下:

    执行结果

    绘制的步骤也很简单:

    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的

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