美文网首页iOS开发经验之谈
绘图-iOS在OC项目中集成Charts绘制图表框架

绘图-iOS在OC项目中集成Charts绘制图表框架

作者: 進无尽 | 来源:发表于2017-09-01 20:42 被阅读485次

    前言

    最近OC项目中使用到了charts做图标绘制,确实是一个很酷并且功能强大的类库。里面包含了各式各样的图标样式,但是使用的是Swift语言编写,所以就涉及到混编的一些操作配置。

    你可以通过两种方式集成进你的项目中:

    • 下载后手动添加 (本文主讲)
    • Cocopods的方式集成

    Charts下载地址

    注意一下使用条件:值得注意的是工程的 Tagerts 最低设置 8.0

    解压后的文件夹里面的内容是这个样子的,如下图:


    导入工程中的步骤

    • 新建工程

      新建工程,取名为ImportChartsDemo.

    • 复制Charts整个文件到ImportChartsDemo工程中

      就是把上图中解压后的文件(剔除红色框中的文件,当然也可以剔除其他一些没有用的文件,由于我没有剔除多余的文件,并最终集成成功,所以就暂时视除了红框内的文件都需要)拷贝到ImportChartsDemo主工程文件夹下。

    • 导入Charts.xcodeproj

      右击项目,选择 -> Add Files to”xx”, 在弹出的选择文件框中选择”Charts.xcodeproj”(注意:不要选择文件夹)。

    • 添加Charts.framework

    找到General->Embedded Binaries,点击+号添加Charts.framework,如下图:

    Embedded Binaries位置

    添加的iOS的framework,如下图:


    添加Charts.framework
    • 建立OC和Swift的桥接文件
      在ImportChartsDemo工程中新建一个Swift文件,名字随便取,这时候会提示是否建立桥接文件,直接选Create Bridging Header 选项,如下图:
      建立桥接文件

    新建完成后,会自动生成一个桥接文件,如下图:


    自动生成的桥接文件
    • 设置编译选项及引入Charts

      1.设置编译选项

      找到Build Settings -> Embedded Content Contains Swift Code 选项,设置为Yes,如下图:


      设置编译选项

      老工程的话是没有上面的设置的,如下图设置即可:


    2.在桥接文件中引入Charts

    如下图:


    引入Charts

    3、桥接文件和开启混编配置。如果后续报错,可以再删掉

    4.在ViewController.m中引入相关头文件
    如下图:

    引入头文件

    引入完成之后,编译一下,如果有错,Clean一下再次编译,编译没有错误说明导入成功.

    项目集成使用中的一些报错

    • dyld: Library not loaded: @rpath/Charts.framework/Charts
    FAEFA9CE-2914-4C86-9334-C9728C47715F.png
    说明 程序里面有动态库。需要配置xcode
    targets -> general -> embedded binaries 在这里添加需要的动态库!
    我这里则需要把Charts.framework添加里面即可。
    如下图
    并开启这个设置
    4AC49923-AB62-40B3-AE9C-84C865C8D961.png
    • 文件未找到

    就算路径对也还是报错

    解决办法:把这两处的都删掉,

    但是文件中要有一个 工程名-Swift.h 的命名的文件才行,否则就报错。

    • 使用XYMarkerView 弹框报错
        XYMarkerView *marker = [[XYMarkerView alloc]
                                initWithColor: [UIColor colorWithWhite:180/255. alpha:1.0]
                                font: [UIFont systemFontOfSize:12.0]
                                textColor: UIColor.whiteColor
                                insets: UIEdgeInsetsMake(8.0, 8.0, 20.0, 8.0)
                                xAxisValueFormatter: _chartView1.xAxis.valueFormatter];
        marker.chartView = _chartView1;
        marker.minimumSize = CGSizeMake(80.f, 40.f);
        _chartView1.marker = marker;
    
    **使用XYMarkerView 时一直报错,查找不到:**
    

    找到了文件

    这个位置也是醉了,不管了,直接拖到新工程中。

      #import "ChartsDemo-Swift.h"
    

    运行报错


    把文件中原来的 字符串“ChartDome” 都换成自己的工程名称即可,这是一个swift转OC的中间文件。

    使用Charts 绘图

    在使用过程中关键所在是要熟悉 Charts中的各种属性设置,而且大部分不同的绘图类文件的属性名称代表的含义一致。

    我在实际的使用中做了封装,使用起来非常简练、方便:

    效果图:

    这几行代码即可搞定

      SCBarChartView * bar = [[SCBarChartView alloc]initWithFrame:CGRectMake(Scale_X(10), Scale_Y(40), WIDTH-Scale_X(20), Scale_Y(350))];
      bar.xArray = @[@"三月",@"四月",@"无语"];
      bar.yArray = @[@30,@50,@18];
      bar.colorArray = @[[UIColor colorWithRed:0.54 green:0.81 blue:0.97 alpha:1.00]];
      bar.yFormat = @"";
      bar.barWidth = 0.5;
      bar.chartLegendTitle = @"食堂统计";
      [bar initBar];
      [self.sc addSubview:bar];
    

    运用细节汇总

    110%看起来很怪,可以设置隐藏起来, spaceTop是展示的Y轴的比例,如果为0则顶部的数值显示不完整,0.05最合适。

         leftAxis.spaceTop = 0.05;
    

    对于使用柱状图展示百分比时。如果分母是 0,那边x坐标轴上会出现 NaN的字样,此时应该判断,如果分母为0,需要把整个值设置为0.

    很多数据挤在一块?想达到动态展开?

    自动展开.gif

    柱形图中

    - (void)setData
    {
        xxxxxxxxxx
        CGFloat flout = self.xArray.count/3.8;         //完美的值
        [_chartView1 zoomAndCenterViewAnimatedWithScaleX:flout scaleY:1 xValue:0 yValue:0 axis:0 duration:1];
      }
    

    分段图中

    - (void)setData
    {
        CGFloat flout = self.xArray.count/7;       //完美的值
        [_chartView zoomAndCenterViewAnimatedWithScaleX:flout scaleY:1 xValue:0 yValue:0 axis:0 duration:1];
    }
    

    折线图中很值得注意的细节

    折线图的自动展开

       方法跟其他类型试图的方法一样
       CGFloat flout = xArray.count/5;
       [_chartView zoomAndCenterViewAnimatedWithScaleX:flout scaleY:1 xValue:0 yValue:0 axis:0 duration:1];
    

    X轴上的数据赋值

      xAxis.valueFormatter = [[DayAxisValueTwoFormatter alloc] initForChart:_chartView :xArray];
    

    X轴上的数据和实际Y轴上的点不对应

      [xAxis setGranularity:1];  //不设置就不均分
    

    X轴最右侧的数据显示不完全

      xAxis.spaceMax = 0.5; 完美解决
    

    隐藏Y轴和Y轴的数据

     ChartYAxis *leftAxis = _chartView1.leftAxis;
     leftAxis.enabled = NO;
    

    对柱状图上数值加上单位

      - (void)setData{
         BarChartData *data = [[BarChartData alloc] initWithDataSets:dataSets];
         data setValueFormatter:<#(id<IChartValueFormatter> _Nullable)#>  // 具体可参照官方dome
      }
    

    值在柱状图的里面还是上面

     - (void)initBar
    {
        _chartView.drawValueAboveBarEnabled = NO;  //设为 YES就是在柱上,设为NO就是在柱内。
    }
    

    点击柱子后获取一个对应的数据?

        <ChartViewDelegate>
    
        _chartView1.delegate = self;
    
        for (int i = start; i < _yArray.count+1; i++)
          {
              if (self.deptNoArray.count != 0) {
                     [yVals addObject:[[BarChartDataEntry alloc] initWithX:i y:[_yArray[i-1] doubleValue] data:self.deptNoArray[i-1]]];
              }else{
                  [yVals addObject:[[BarChartDataEntry alloc] initWithX:i y:[_yArray[i-1] doubleValue]]];
              }
          }
     
        - (void)chartValueSelected:(ChartViewBase *)chartView entry:(ChartDataEntry *)entry   highlight:(ChartHighlight *)highlight
      {
            if (self.pushNextDept) { //是否可以跳转。如果不跳转就会弹框显示对应的数值
            NSString *deptNoStr = (NSString *)entry.data;
         
            }
       }
    

    设置Y轴上、柱状图上的数字千位加分割号

    Y轴上的数字千位加分割号:

    NSNumberFormatter *leftAxisFormatter = [[NSNumberFormatter alloc] init];
    leftAxisFormatter.minimumFractionDigits = 0;
    leftAxisFormatter.maximumFractionDigits = 1;
    leftAxisFormatter.negativeSuffix = self.yFormat;
    leftAxisFormatter.positiveSuffix = self.yFormat;
    #####下面这两句设置是实现的关键
    [leftAxisFormatter setFormatterBehavior: NSNumberFormatterBehavior10_4];
    [leftAxisFormatter setNumberStyle: NSNumberFormatterDecimalStyle];
    
    ChartYAxis *leftAxis = _chartView1.leftAxis;
    leftAxis.labelFont = [UIFont systemFontOfSize:11.f];
    leftAxis.labelCount = 8;
    leftAxis.valueFormatter = [[ChartDefaultAxisValueFormatter alloc] initWithFormatter:leftAxisFormatter];
    leftAxis.labelPosition = YAxisLabelPositionOutsideChart;
    

    柱状图的数字千位加分割号:

    BarChartData *data = [[BarChartData alloc] initWithDataSets:dataSets];
    [data setValueFont:[UIFont fontWithName:@"Helvetica" size:MEDIUM_FONT]];
    [data setValueFormatter:[[ChartDataFormat alloc]init]];
    
    ChartDataFormat 类实现:
    *******************************************
    #import <Foundation/Foundation.h>
    #import "sunCanteen-Swift.h"
    
    @interface ChartDataFormat : NSObject
    <IChartValueFormatter>
    @end
    
    #import "ChartDataFormat.h"
    @implementation ChartDataFormat
    
    - (NSString *)stringForValue:(double)value entry:(ChartDataEntry *)entry dataSetIndex:(NSInteger)dataSetIndex viewPortHandler:(ChartViewPortHandler *)viewPortHandler
    {
        if (value ==  0) {
            return @"";
        }else{
            NSNumberFormatter *moneyFormatter = [[NSNumberFormatter alloc] init];
            moneyFormatter.positiveFormat = @"###,##0";
            NSString *formatString = [moneyFormatter stringFromNumber:[NSNumber numberWithDouble:value]];
            return formatString;
        }
    }
    @end
    

    X轴上文字很长被遮挡?

    ChartXAxis *xAxis = _chartView1.xAxis;
    xAxis.labelPosition = XAxisLabelPositionBottom;
    xAxis.labelFont = [UIFont systemFontOfSize:11.f];
    xAxis.drawGridLinesEnabled = NO;
    xAxis.granularity = 1.0; // only intervals of 1 day
    xAxis.labelCount = 7;
    xAxis.wordWrapEnabled = YES;  //文字换行
    xAxis.valueFormatter = [[DayAxisValueFormatter alloc] initForChart:_chartView1 :_xArray];
    #### 这是重点
    [xAxis setLabelRotationAngle:30]; 
    

    分段柱状图中不显示数值

    - (void)setData{     中
         BarChartData *data = [[BarChartData alloc] initWithDataSets:dataSets];
         [data setDrawValues:NO]; // 可隐藏数值
    }
    

    分段柱状图中点击不显示/显示阴影框

    点击分段柱状图任意分段,整条都是选中状态?

    - (void)initBar{
        _chartView.highlightFullBarEnabled = YES;
    }
    

    不显示/显示阴影框?

    - (void)initBar{
        XYMarkerView *marker = [[XYMarkerView alloc]
                            initWithColor: [UIColor blackColor]
                            font: [UIFont systemFontOfSize:12.0]
                            textColor: UIColor.whiteColor
                            insets: UIEdgeInsetsMake(8.0, 8.0, 20.0, 8.0)
                            xAxisValueFormatter: _chartView.xAxis.valueFormatter];
        marker.chartView = _chartView;
        marker.minimumSize = CGSizeMake(80.f, 40.f);
        if (self.showMask) { //需要显示就显示,不需要就不显示
             _chartView.marker = marker;
        }
    }
    

    怎样实现如图中阴影框中的多条显示数据?

    1.//组装数据
    - (void)setData
    {
        NSMutableArray *yVals = [[NSMutableArray alloc] init];
        
        //点击柱状图上弹框显示的具体分段文本值
        NSMutableString *markStr = [NSMutableString stringWithFormat:@""];
        for (int i = 0; i<self.colorTitleArray.count; i++) {
            NSString *str = self.colorTitleArray[i];
            if (i==0) {
                [markStr appendString:[NSString stringWithFormat:@"%@",str]];
            }else{
                [markStr appendString:[NSString stringWithFormat:@":%@",str]];
            }
            
        }
        //+++++++++++++++++++++++++++++++++
        
        for (int i = 0; i < _yArray.count; i++){
            
            NSDictionary *dic = _yArray[i];
            NSMutableArray *yValues = [[NSMutableArray alloc]initWithCapacity:0];
            for (int i = 0; i < dic.count; i++)
            {
                [yValues addObject:[dic objectForKey:[NSString stringWithFormat:@"%d",i]]];
            }
            
            if (self.deptNoArray.count != 0) {
                NSDictionary *areaInfo = @{@"deptName":self.xArray[i],@"deptNo":self.deptNoArray[i],@"mark":markStr};
                [yVals addObject:[[BarChartDataEntry alloc] initWithX:i yValues:yValues data:areaInfo]];
            }else{
                [yVals addObject:[[BarChartDataEntry alloc] initWithX:i yValues:yValues]];
            }
        }
    }
    
    2.修改 XYMarkerView.swift 中的代码
    
    open override func refreshContent(entry: ChartDataEntry, highlight: Highlight)
    {
        let entry1 = entry as! BarChartDataEntry
        let markStr = entry1.data?["mark"] as! String
        let markStrArray:[String] = markStr.components(separatedBy:":")
        let array1 = entry1.yValues
        var allMarkText = ""
        for(indexs,item) in (array1?.enumerated())!{
            allMarkText += "\n\(markStrArray[indexs]):\(item)"
        }
        print("allMarkText\(allMarkText)")
        setLabel(xAxisValueFormatter!.stringForValue(entry.x, axis: nil)  + allMarkText)
    }
    

    详细的使用中的参数设置可以参考如下两篇文章:

    iOS使用Charts框架绘制—柱形图
    iOS使用Charts框架绘制折线图

    小结

    以上大概就是我使用 Charts这个绘图类库的笔记了,如有错误之处,请留言指正,后续如果有新的心得总结会更新此文。另外一款绘图第三方也很不错AAChartKit,有纯OC版和纯Swift版,不像本文中的Charts是OC和Swfit的混合,集成起来有点麻烦和易出错。

    相关文章

      网友评论

      • 大萌哥哥:您好,分组barchart X轴数据和图表不对应怎么解决呀,急
      • Mister_H:写的很好,请问分段柱状图是怎么设置的?demo里没有找到
        Mister_H:@進无尽 好的,我再找找,感谢:pray:
        進无尽:@Mister_H dome里面有的,你仔细找下,都是BarChartView这个类,只是每一个X对应多个Y值。
      • 飞翔de小苹果:你好,请问怎么实现双柱形,对比图,不是叠加图?
        進无尽:@飞翔de小苹果 下载Charts的Dome,参看里面的功能即可。
      • Evyn_:怎么下来的集成方法不行啊 Charts.frameworkIOS找不到,只有MAC os的framework。我用的是xcode 9 oc的项目。求指导
        進无尽:我的工程不是Xcode9的项目,不过导入Charts.xcodeproj后 在Tagets的General->Embedded Binaries,点击+号应该是可以添加Charts.framework的。

      本文标题:绘图-iOS在OC项目中集成Charts绘制图表框架

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