美文网首页专注iOS开发常用组件iOS动画
iOS封装一个简单的曲线图表视图

iOS封装一个简单的曲线图表视图

作者: wazrx | 来源:发表于2016-04-06 10:31 被阅读3908次

写在前面

前段时间做汇率的项目中,需要绘制汇率曲线,虽然知道关于图表相关的三方库,github已经有很多大神级作品,但是我还是想自己尝试写一下,也是学习的过程嘛,所以我就自己按照项目需求做了个曲线图表视图,并进行了简单封装,效果如图:

图1:项目中的效果,模拟器对背后的网格显示有点问题,可以忽略

t1.gif

图2:简单的demo截图

t2.gif

功能

如上图,控件主要包含了几个功能点

1、绘制曲线

2、填充曲线围绕部分

3、背后网格线

4、左侧的行标和下方的列标显示

如何使用

github地址:封装一个简单的曲线图表视图XWCurveView,使用步骤如下:

1、导入XWCurveView.h头文件

2、初始化控件,设置pointValues属性,该属性为所有的绘制点的值的数组,每个绘制点用字典表示,字典必须包含key值为 XWCurveViewPointValuesRowValueKeyXWCurveViewPointValuesColumnValueKey 分别代表横纵的值,

3、配置其他可选的属性值

4、调用- (void)xw_drawCurveView;进行绘制或者重绘曲线视图

原理

绘制原理很简单,使用了CAShapeLayer + UIBezierPath,我们需要将pointValues中的所有值转换成控件中的坐标值,然后根据坐标值得到path即能得到曲线,转换的时候需要考虑到每个点的坐标和横纵最值的关系,最值可以手动设置,但如果没设置,可以通过pointValues计算得到最值,背后的网格我使用了CAReplicatorLayer,这是创建重复控件的利器,下面是主要的代码

/**
 *  整理传入的坐标值,按传入数据的值的横坐标值从小到大排序一下
 */
- (void)xwp_sortPointValues{
    NSMutableArray *temp = [NSMutableArray arrayWithArray:_pointValues];
    [temp sortUsingComparator:^NSComparisonResult(NSDictionary *obj1, NSDictionary *obj2) {
        if ([obj1[XWCurveViewPointValuesRowValueKey] floatValue] > [obj2[XWCurveViewPointValuesRowValueKey] floatValue]) {
            return NSOrderedDescending;
        }else{
            return NSOrderedAscending;
        }
    }];
    _pointValues = temp.copy;
}

/**
 *  计算横纵坐标的最值,如果没有设置就使用计算的最值
 */
- (void)xwp_checkEdgeValues{
    CGFloat rowMax = [_pointValues.lastObject[XWCurveViewPointValuesRowValueKey] floatValue];
    CGFloat rowMin = [_pointValues.firstObject[XWCurveViewPointValuesRowValueKey] floatValue];
    CGFloat columnMax = -MAXFLOAT;
    CGFloat columnMin = MAXFLOAT;
    for (NSDictionary *pointValue in _pointValues) {
        if ([pointValue[XWCurveViewPointValuesColumnValueKey] floatValue] > columnMax) {
            columnMax = [pointValue[XWCurveViewPointValuesColumnValueKey] floatValue];
        }
        if ([pointValue[XWCurveViewPointValuesColumnValueKey] floatValue] < columnMin) {
            columnMin = [pointValue[XWCurveViewPointValuesColumnValueKey] floatValue];
        }
    }
    if (!_rowMaxSettedFlag) {
        _rowMaxValue = rowMax;
    }
    if (!_rowMinSettedFlag) {
        _rowMinValue = rowMin;
    }
    if (!_columnMaxSettedFlag) {
        _columnMaxValue = columnMax;
    }
    if (!_columnMinSettedFlag) {
        _columnMinValue = columnMin;
    }
}


/**
 *  转换,将传入的点的值数组转换为坐标数组
 */
- (void)xwp_changePointArrayFromValueArray{
    _pointArray = @[].mutableCopy;
    for (NSDictionary *dict in _pointValues) {
        CGPoint point = [self xwp_changePointFromValue:dict];
        [_pointArray addObject:[NSValue valueWithCGPoint:point]];
    }
}

/**
 *  将传入的点根据值转换为坐标
 */
- (CGPoint)xwp_changePointFromValue:(NSDictionary *)dict{
    CGFloat rowValue = [dict[XWCurveViewPointValuesRowValueKey] floatValue];
    CGFloat columnValue = [dict[XWCurveViewPointValuesColumnValueKey] floatValue];
    CGPoint point = CGPointMake(_mainContainer.width / (_rowMaxValue - _rowMinValue) * (rowValue - _rowMinValue), _mainContainer.height / (_columnMaxValue - _columnMinValue) * (_columnMaxValue - columnValue));
    return point;
}

/**
 *  根据转换的坐标点构建绘制曲线的path和填充曲线的path
 */

- (void)xwp_makePath{
    UIBezierPath * path = [UIBezierPath bezierPath];
    UIBezierPath *backPath = [UIBezierPath bezierPath];
    CGPoint firstPoint = [_pointArray[0] CGPointValue];
    CGPoint lastPoint = [_pointArray[_pointArray.count - 1] CGPointValue];
    [path moveToPoint:firstPoint];
    [backPath moveToPoint:CGPointMake(firstPoint.x, _mainContainer.height)];
    for (NSValue *pointValue in _pointArray) {
        CGPoint point = [pointValue CGPointValue];
        if (pointValue == _pointArray[0]) {
            [backPath addLineToPoint:point];
            continue;
        }
        [backPath addLineToPoint:point];
        [path addLineToPoint:point];
    }
    [backPath addLineToPoint:CGPointMake(lastPoint.x, _mainContainer.height)];
    _path = path;
    _backPath = backPath;
}

/**
 *  根据path绘制曲线
 */

- (void)xwp_drawCurveWithPath{
    _backLayer.path = _backPath.CGPath;
    _curveLineLayer.path = _path.CGPath;
    _curveLineLayer.strokeEnd = 1;
    if (_drawWithAnimation) {
        CABasicAnimation *pointAnim = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
        pointAnim.fromValue = @0;
        pointAnim.toValue = @1;
        pointAnim.duration = _drawAnimationDuration;
        [_curveLineLayer addAnimation:pointAnim forKey:@"drawLine"];
    }
}

/**
 *  上面除了绘制的操作,关于计算点和path的操作最后都应该在异步线程进行,如果点过多,会造成主线程阻塞
 */
- (void)xwp_setCurveLine{
    if (!_pointValues.count) {
        NSLog(@"pointValues为空,没有可绘制的点");
        return;
    }
    dispatch_async(dispatch_queue_create("处理计算点和path的队列", NULL), ^{
        [self xwp_sortPointValues];
        [self xwp_checkEdgeValues];
        [self xwp_changePointArrayFromValueArray];
        [self xwp_makePath];
        dispatch_async(dispatch_get_main_queue(), ^{
            [self xwp_drawCurveWithPath];
        });
    });
}

4、如上就是主要的曲线绘制代码了,逻辑是非常简单的,其它细节代码请查看源代码

最后

控件比较简单,我仅仅是对自己的思路做了个总结,自己实现过一次毕竟印象要深刻许多,要是自己以后还要用到这类功能有能更快的集成了,github地址:封装一个简单的曲线图表视图XWCurveView,若有什么好的意见欢迎留言,如果觉得有帮助,感谢star,谢谢!

相关文章

  • iOS封装一个简单的曲线图表视图

    写在前面 前段时间做汇率的项目中,需要绘制汇率曲线,虽然知道关于图表相关的三方库,github已经有很多大神级作品...

  • TEAChart

    # 一个简单直观的iOS 图表库。

  • iOS-自定义控件相关

    本篇涵盖自定义控件、视图等. 1.iOS开发-轻松学会封装自定义视图view(自定义弹框封装详解)2.iOS开发-...

  • React Native封装Android自定义原生控件

    通过封装一个简单的视图控件CustomView来介绍使用React Native来封装android组件的方法。 ...

  • 轻松实现 Android 图表 • ECharts

    本文是关于 Android 图表实现的一个实践笔记。简单封装百度的 ECharts,轻松实现各种图表效果。 相关 ...

  • 文章收集

    关于视图的周期流程一篇文章揭秘 iOS 布局相关问题 封装SDK流程iOS 自己封装的SDK 打包与合并,新手教程...

  • iOS封装 引导视图的封装

    最近公司项目需求要做一个页面的引导视图,就长这个样子 自己平时开发过程中喜欢将可以封装的控件尽量封装,这样既可以锻...

  • iOS 模态视图

    概念 ios开发中,在当前视图上再弹出一个视图(模态视图)例如登陆视图,分享视图,注册等等。 说明 实现一个简单的...

  • 图表的运用

    今天学习图表的运用。在学函数、数据透视图之后,开启了进阶课程——用图表来展示数据。 如何制作一个简单有效的表...

  • iOS视图封装 - DJCarouselView

    DJCarouselView 一个可以无限滚动的轮播图 功能 自定义图片的加载方式,不依赖任何图片加载库 图片可以...

网友评论

  • Jackie_123:楼主,这个是用mardown写的吗?
  • LambZhou:你好!像图一把手放在曲线图上,自动显示当前位置的日期和值的效果怎么做啊?里面的Delagate该怎么用?
  • _Sven: :smiley: 感谢分享,学习了。
  • 民谣程序员:用html5绘制也挺容易的

本文标题:iOS封装一个简单的曲线图表视图

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