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

前言

最近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的混合,集成起来有点麻烦和易出错。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容