【iOS 開發】Objective-C 中 Charts 的 CombinedChart 使用匯總

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,460評論 6 538
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,067評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 177,467評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,468評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,184評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,582評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,616評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,794評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,343評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,096評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,291評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,863評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,513評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,941評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,190評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,026評論 3 396
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,253評論 2 375

推薦閱讀更多精彩內容