【iOS 开发】Objective-C 中 Charts 的 CombinedChart 使用汇总

2017-08-10 18:22:58 Joaquín

最近公司项目中要做一个报表功能,需要用到图表,于是就使用了 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 *)bar1Valuesbar2Values:(NSArray*)bar2Values{

    NSMutableArray *barEntries= [NSMutableArray array];
    if (bar1Values.count== bar2Values.count){

        for (int i=0; i<bar1Values.count; i++) {

            BarChartDataEntry*barEntry= [[BarChartDataEntryalloc] initWithX:i yValues:@[bar1Values[i],bar2Values[i]]];
            [barEntriesaddObject:barEntry];
        }
    }

    BarChartDataSet*dataSet = [[BarChartDataSetalloc] initWithValues:barEntries];
    dataSet.colors = @[[UIColor greenColor], [UIColor blueColor]];
    dataSet.axisDependency = AxisDependencyLeft; // 根据左边数据显示
    dataSet.drawValuesEnabled = NO; // 是否显示数据

    BarChartData*data = [[BarChartDataalloc] 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 轴动画
}

另外这里有一个坑,在设置 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

相关帖子
用户评论
开源开发学习小组列表