美文网首页自己尝试等装一下牛叉的demo学无止境
【iOS 开发】Objective-C 中 Charts 的 C

【iOS 开发】Objective-C 中 Charts 的 C

作者: 爱吃鸭梨的猫 | 来源:发表于2017-08-10 15:00 被阅读307次
    CombinedChart

    最近公司项目中要做一个报表功能,需要用到图表,于是就使用了 Charts 这个框架,这个框架可以说是图表中用的最多的框架了,由于 Charts 只有 Swift 版本,公司项目是用 OC 写的,所以先整理一下 OC 的使用方法,Swift 等以后项目转了在整理。


    1. 创建 CombinedChartView 并设置属性

    下面列出一些常用的设置属性,可以根据需求自行设置。

    @interface CombinedChartViewController()
    
    @property (nonatomic, strong) CombinedChartView *combinedChartView; // 柱状折线组合图
    
    @end
    
    @implementation CombinedChartViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        /* 设置图表的属性 */
        _combinedChartView = [[CombinedChartView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 350)];
        _combinedChartView.drawOrder = @[@(CombinedChartDrawOrderBar), @(CombinedChartDrawOrderLine)]; // 绘制顺序(折线图在柱状图上面)
        _combinedChartView.noDataText = @"暂无数据"; // 无数据时显示的文字
        _combinedChartView.descriptionText = @""; // 描述文字
        _combinedChartView.legend.enabled = NO; // 隐藏图例
        _combinedChartView.pinchZoomEnabled = NO; // 触控放大
        _combinedChartView.doubleTapToZoomEnabled = NO; // 双击放大
        _combinedChartView.scaleXEnabled = NO; // X 轴缩放
        _combinedChartView.scaleYEnabled = NO; // Y 轴缩放
        _combinedChartView.scaleEnabled = NO; // 缩放
        _combinedChartView.highlightPerTapEnabled = NO; // 单击高亮
        _combinedChartView.highlightPerDragEnabled = NO; // 拖拽高亮
        _combinedChartView.dragEnabled = YES; // 拖拽图表
        _combinedChartView.dragDecelerationEnabled = YES; // 拖拽后是否有惯性效果
        _combinedChartView.dragDecelerationFrictionCoef = 0.5; // 拖拽后惯性效果的摩擦系数(0~1),数值越小,惯性越不明显
        [self.view addSubview:_combinedChartView];
    
        /* 设置 X 轴显示的值的属性 */
        ChartXAxis *xAxis = _combinedChartView.xAxis;
        xAxis.labelPosition = XAxisLabelPositionBottom; // 显示位置
        xAxis.drawGridLinesEnabled = NO; // 网格绘制
        xAxis.axisLineColor = [UIColor lightGrayColor]; // X 轴颜色
        xAxis.axisLineWidth = 0.5f; // X 轴线宽
        xAxis.labelFont = [UIFont systemFontOfSize:10]; // 字号
        xAxis.labelTextColor = [UIColor lightGrayColor]; // 颜色
        xAxis.labelRotationAngle = 30; // 文字倾斜角度
    
        /* 设置左侧 Y 轴显示的值的属性 */
        ChartYAxis *leftAxis = _combinedChartView.leftAxis;
        leftAxis.labelPosition = YAxisLabelPositionOutsideChart; // 显示位置
        leftAxis.drawGridLinesEnabled = YES; // 网格绘制
        leftAxis.gridColor = [UIColor lightGrayColor]; // 网格颜色
        leftAxis.gridLineWidth = 0.5f; // 网格线宽
        leftAxis.drawAxisLineEnabled = NO; // 是否显示轴线
        leftAxis.labelFont = [UIFont systemFontOfSize:10]; // 字号
        leftAxis.labelTextColor = [UIColor lightGrayColor]; // 颜色
        leftAxis.axisMinimum = 0; // 最小值
        leftAxis.axisMaximum = 500; // 最大值(不设置会根据数据自动设置)
        [leftAxis setLabelCount:6 force:YES]; // Y 轴段数(会自动分成对应段数)
    
        /* 设置右侧 Y 轴显示的值的属性 */
        ChartYAxis *rightAxis = _combinedChartView.rightAxis;
        rightAxis.labelPosition = YAxisLabelPositionOutsideChart; // 显示位置
        rightAxis.drawGridLinesEnabled = NO; // 网格绘制
        rightAxis.drawAxisLineEnabled = NO; // 是否显示轴线
        rightAxis.labelFont = [UIFont systemFontOfSize:10]; // 字号
        rightAxis.labelTextColor = [UIColor lightGrayColor]; // 颜色
        rightAxis.axisMinimum = 0; // 最小值
        rightAxis.axisMaximum = 100; // 最大值(不设置会根据数据自动设置)
        [rightAxis setLabelCount:6 force:YES]; // Y 轴段数(会自动分成对应段数)
    }
    
    @end
    

    2. 设置柱状图属性

    下面将设置柱状图属性与数据进行了封装。

    /**
     柱状图的数据
    
     @param bar1Values 第一段的数据
     @param bar2Values 第二段的数据
     @return 柱状图的数据
     */
    - (BarChartData *)getBarData:(NSArray *)bar1Values bar2Values:(NSArray *)bar2Values {
        
        NSMutableArray *barEntries = [NSMutableArray array];
        if (bar1Values.count == bar2Values.count) {
            
            for (int i=0; i<bar1Values.count; i++) {
                
                BarChartDataEntry *barEntry = [[BarChartDataEntry alloc] initWithX:i yValues:@[bar1Values[i], bar2Values[i]]];
                [barEntries addObject:barEntry];
            }
        }
        
        BarChartDataSet *dataSet = [[BarChartDataSet alloc] initWithValues:barEntries];
        dataSet.colors = @[[UIColor greenColor], [UIColor blueColor]];
        dataSet.axisDependency = AxisDependencyLeft; // 根据左边数据显示
        dataSet.drawValuesEnabled = NO; // 是否显示数据
        
        BarChartData *data = [[BarChartData alloc] initWithDataSets:@[dataSet]];
        data.barWidth = 0.55f; // 柱状图宽度(数值范围 0 ~ 1)
        
        return data;
    }
    

    3. 设置折线图属性

    下面将设置折线图属性与数据进行了封装。

    /**
     获取折线图的数据
    
     @param lineValues 数据放入数组 NSNumber 类型
     @return 折线图的数据
     */
    - (LineChartData *)getLineData:(NSArray *)lineValues {
        
        NSMutableArray *entries = [NSMutableArray array];
        for (int i = 0; i < lineValues.count; i++) {
            
            ChartDataEntry *entry = [[ChartDataEntry alloc] initWithX:i y:[lineValues[i] floatValue]];
            [entries addObject:entry];
        }
        
        LineChartDataSet *dataSet = [[LineChartDataSet alloc] initWithValues:entries];
        dataSet.colors = @[[UIColor orangeColor]]; // 线的颜色
        dataSet.lineWidth = 0.5f; // 线宽
        dataSet.circleRadius = 2.5f; // 圆点外圆半径
        dataSet.circleHoleRadius = 1.5f; // 圆点内圆半径
        dataSet.circleColors = @[[UIColor orangeColor]]; // 圆点外圆颜色
        dataSet.circleHoleColor = [UIColor whiteColor]; // 圆点内圆颜色
        dataSet.axisDependency = AxisDependencyRight; // 根据右边数据显示
        dataSet.drawValuesEnabled = NO; // 是否显示数据
        dataSet.mode = LineChartModeCubicBezier; // 折线图类型
        dataSet.drawFilledEnabled = YES; // 是否显示折线图阴影
        NSArray *shadowColors = @[(id)[[UIColor orangeColor] colorWithAlphaComponent:0].CGColor, (id)[[UIColor orangeColor] colorWithAlphaComponent:0.7].CGColor];
        CGGradientRef gradient = CGGradientCreateWithColors(nil, (CFArrayRef)shadowColors, nil);
        dataSet.fill = [ChartFill fillWithLinearGradient:gradient angle:90.0f]; // 阴影渐变效果
        dataSet.fillAlpha = 1.0f; // 阴影透明度
        LineChartData *lineData = [[LineChartData alloc] initWithDataSet:dataSet];
        
        return lineData;
    }
    

    4. 设置图表数据

    最后通过以下方法就能够设置整个图表的数据。

    /**
     设置混合图表的数据
    
     @param xValues X 轴的数据
     @param bar1Values 柱状图数据1
     @param bar2Values 柱状图数据2
     @param lineValues 折线图数据
     */
    - (void)setXValues:(NSArray *)xValues
            bar1Values:(NSArray *)bar1Values
            bar2Values:(NSArray *)bar2Values
            lineValues:(NSArray *)lineValues {
        
        CombinedChartData *data = [[CombinedChartData alloc] init];
        data.barData = [self getBarData:bar1Values bar2Values:bar2Values]; // 柱状图数据
        data.lineData = [self getLineData:lineValues]; // 折线图数据
        [_combinedChartView setData:data]; // 图表数据
        
        ChartXAxis *xAxis = _combinedChartView.xAxis;
        xAxis.axisMinimum = data.xMin - 0.5f; // X 轴最小数量
        xAxis.axisMaximum = data.xMax + 0.5f; // X 轴最大数量
        xAxis.valueFormatter = [[ChartIndexAxisValueFormatter alloc] initWithValues:xValues]; // X 轴数据
        
        [_combinedChartView setVisibleXRangeMaximum:7]; // X 轴最多显示数量(其余可滑动显示)
        [_combinedChartView animateWithYAxisDuration:1.0]; // 添加 Y 轴动画
        [_combinedChartView notifyDataSetChanged]; // 通知数据改变
    }
    

    另外这里有一个坑,在设置 X 轴属性的时候,有个属性是 xAxis.labelWidth ,由于图表好像是自动计算 label 大小的,设置这个属性根本没有任何作用,所以就导致当 X 轴数据文字过长时,就全部挤在一块了,为了解决这个问题,可以在设置 xAxis.valueFormatter 的时候自定义一个 valueFormatter 来设定指定宽度截取,下面是我的自定义。

    CustomAxisValueFormatter.h

    @interface CustomAxisValueFormatter : NSObject <IChartAxisValueFormatter>
    
    - (instancetype)initWithValues:(NSArray *)values labelWidth:(CGFloat)labelWidth;
    
    @end
    

    CustomAxisValueFormatter.m

    @interface CustomAxisValueFormatter ()
    
    @property (nonatomic, strong) NSArray *values;
    @property (nonatomic, assign) CGFloat labelWidth;
    
    @end
    
    @implementation CustomAxisValueFormatter
    
    - (instancetype)initWithValues:(NSArray *)values labelWidth:(CGFloat)labelWidth
    {
        self = [super init];
        if (self) {
            
            _values = values;
            _labelWidth = labelWidth;
        }
        return self;
    }
    
    - (NSString *)stringForValue:(double)value axis:(ChartAxisBase *)axis {
        
        /* 根据设置的字符宽度自动截取字符长度 */
        NSString *result = @"";
        NSInteger index = @(value).integerValue;
        if (index < _values.count) {
            
            result = _values[index];
            if (_labelWidth > 0) {
                
                UILabel *label = [[UILabel alloc] init];
                label.font = [UIFont systemFontOfSize:10]; // 这里和 X 轴文字字号设置一样大
                label.text = result;
                while ([label sizeThatFits:CGSizeMake(MAXFLOAT, MAXFLOAT)].width > _labelWidth) {
                    
                    result = [result substringToIndex:result.length - 1];
                    label.text = [NSString stringWithFormat:@"%@...", result];
                }
                return label.text;
            }
        }
        
        return result;
    }
    
    @end
    

    这是之前设置 xAxis.valueFormatter 的方法。

    xAxis.valueFormatter = [[ChartIndexAxisValueFormatter alloc] initWithValues:xValues];
    

    改为自定义的方法。

    xAxis.valueFormatter = [[CustomAxisValueFormatter alloc] initWithValues:xValues labelWidth:40];
    

    5. 设置数据方法

    图表的数据全部放入数组中,数字用 NSNumber 类型。

    [self setXValues:@[@"X轴数据1", @"X轴数据2", @"X轴数据3"] bar1Values:@[@"10", @"20", @"30"] bar2Values:@[@"30", @"20", @"10"] lineValues:@[@"40", @"50", @"60"]];
    

    下面是我们项目做出来的显示效果:

    图表显示效果

    其实 CombinedChartView 混合图表只是将 BarChartView 柱状图和 LineChartView 折线图合在一起了,设置还是分开设置的,所以不管是柱状图还是折线图,都可以参照上面来设置。

    将来的你,一定会感激现在拼命的自己,愿自己与读者的开发之路无限美好。

    我的传送门: 博客简书微博GitHub

    相关文章

      网友评论

      • skylor:你好!请问有demo吗?谢谢
      • 小北风sky:xAxis.valueFormatter = [[ChartIndexAxisValueFormatter alloc] initWithValues:xValues]; // X 轴数据

        这句我设置为什么不起作用呢
      • 天涯浪子ou:你好!画曲线的时候 起点从哪个位置开始画 可以设置吗
        爱吃鸭梨的猫:起点是根据X轴数值自动设置的,好像不可以另外设置。

      本文标题:【iOS 开发】Objective-C 中 Charts 的 C

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