iOS繪制3D餅圖的實(shí)現(xiàn)方法
實(shí)現(xiàn)核心
1.壓縮餅圖,使餅圖有3D的效果,并不是真正的畫了個(gè)3D圓柱
2.繪制厚度,帶陰影效果,讓看上去像是圓柱的高
3.路徑添加好了,用顏色填充后繪制一下,添加陰影后還需繪制一遍
餅圖添加陰影的思考
之前這加陰影的一段不是很明白,為啥設(shè)顏色和陰影都要draw一次
進(jìn)過反復(fù)的測(cè)試,我自己分析了一下,每次draw一下想當(dāng)于,把當(dāng)前的設(shè)置畫出來(lái),再次draw就在這基礎(chǔ)上,再畫最近的設(shè)置,這里加顏色和陰影就像是一層一層的畫上去。要是不draw的話,再設(shè)置顏色相當(dāng)于重新設(shè)置了顏色,之前設(shè)置的顏色就無(wú)效了。同時(shí)要結(jié)合path使用,如果設(shè)置一場(chǎng)顏色draw一次,再設(shè)置顏色draw一次,后面設(shè)置的顏色是無(wú)用的。需要添加陰影的部分,需要用path路徑繪制。
效果圖

3D餅圖的核心代碼如下:
#import "SSSolidCakeView.h"
@implementation SSSolidCakeView
#pragma mark 重寫繪制方法
- (void)drawRect:(CGRect)rect
{
//第一步獲得上下文
CGContextRef cakeContextRef = UIGraphicsGetCurrentContext();
//反鋸齒,讓圖形邊緣更加柔和(Sets whether or not to allow anti-aliasing for a graphics context.)
CGContextSetAllowsAntialiasing(cakeContextRef, TRUE);
//縮放坐標(biāo)系的比例,通過設(shè)置y軸壓縮,然后畫代陰影的厚度,就畫出了像是3D餅圖的效果
CGContextScaleCTM(cakeContextRef, _xScale, _yScale);
//餅圖最先的起始角度
CGFloat startAngle =0;
for (int i = 0; i<_dataArray.count; i++) {
//畫餅的橫截面,上一部分完整的圓
//cake當(dāng)前的角度
CGFloat currentAngle = [_dataArray[i] floatValue];
//結(jié)束的角度
CGFloat endAngle = startAngle + currentAngle;
//每一塊cake的起點(diǎn),也就是圓心
CGContextMoveToPoint(cakeContextRef, _cakeCenter.x, _cakeCenter.y);
//添加對(duì)應(yīng)角度扇形
CGContextAddArc(cakeContextRef, _cakeCenter.x, _cakeCenter.y, _cakeRadius, startAngle*M_PI*2, endAngle*M_PI*2, 0);
//得到對(duì)應(yīng)的顏色
UIColor *currentColor = _colorArray[i];
//設(shè)置邊界顏色
CGContextSetStrokeColorWithColor(cakeContextRef, currentColor.CGColor);
//設(shè)置填充顏色
CGContextSetFillColorWithColor(cakeContextRef, currentColor.CGColor);
//畫子路徑,這里就繪制還不是在畫完厚度再繪制,是因?yàn)椴⒉恍枰L制所有cake的厚度,但是上一部分的圓是都要繪制的
CGContextDrawPath(cakeContextRef, kCGPathFill);
//餅圖上一部分圓,startAngle處的起點(diǎn)坐標(biāo)
CGFloat upStartX = _cakeCenter.x+_cakeRadius*cos(startAngle*2*M_PI);
CGFloat upStartY = _cakeCenter.y+_cakeRadius*sin(startAngle*2*M_PI);
//餅圖上一部分圓,endAngle處的終點(diǎn)坐標(biāo)
CGFloat upEndX = _cakeCenter.x+_cakeRadius*cos(endAngle*2*M_PI);
CGFloat upEndY = _cakeCenter.y+_cakeRadius*sin(endAngle*2*M_PI);
//餅圖厚度在角度結(jié)束處y坐標(biāo)
CGFloat downEndY = upEndY + _cakeHeight;
//畫圓柱的側(cè)面,餅圖的厚度,圓柱的前半部分能看到,后半部分是看不到
//開始的角度如果>=M_PI,就會(huì)在圓柱的后面,側(cè)面厚度就沒必要畫了
if (startAngle<0.5) {
//繪制厚度
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, nil, upStartX, upStartY);
//當(dāng)結(jié)束的角度>0.5*2*M_PI時(shí),結(jié)束的角度該是M_PI的地方(視覺原因)
if (endAngle>0.5) {
//上部分的弧
CGPathAddArc(path, nil, _cakeCenter.x, _cakeCenter.y, _cakeRadius, startAngle*2*M_PI, M_PI, 0);
//在角度結(jié)束的地方,上部分到下部分的直線
CGPathAddLineToPoint(path, nil, _cakeCenter.x-_cakeRadius, _cakeCenter.y+_cakeHeight);
//下部分的弧
CGPathAddArc(path, nil, _cakeCenter.x, _cakeCenter.y + _cakeHeight, _cakeRadius, M_PI, startAngle*2*M_PI, 1);
//在角度開始的地方,從下部分到上部分的直線
CGPathAddLineToPoint(path, nil, upStartX, upStartY);
}
else{
//上部分的弧
CGPathAddArc(path, nil, _cakeCenter.x, _cakeCenter.y, _cakeRadius, startAngle*2*M_PI, endAngle*2*M_PI, 0);
//在角度結(jié)束的地方,上部分到下部分的直線
CGPathAddLineToPoint(path, nil, upEndX, downEndY);
//下部分的弧
CGPathAddArc(path, nil, _cakeCenter.x, _cakeCenter.y + _cakeHeight, _cakeRadius, endAngle*2*M_PI, startAngle*2*M_PI, 1);
//在角度開始的地方,從下部分到上部分的直線
CGPathAddLineToPoint(path, nil, upStartX, upStartY);
}
//之前這一段不是很明白,為啥設(shè)顏色和陰影都要draw一次
//我自己嘗試并理解分析了一下,每次draw一下想當(dāng)于,把當(dāng)前的設(shè)置畫出來(lái),再次draw就在這基礎(chǔ)上,再畫當(dāng)前的設(shè)置,這里加顏色和陰影就是一層一層的畫上去。要是不draw的話,再設(shè)置顏色相當(dāng)于重新設(shè)置了顏色,之前設(shè)置的顏色就無(wú)效了。
CGContextAddPath(cakeContextRef, path);
CGContextDrawPath(cakeContextRef, kCGPathFill);
//加陰影
[[UIColor colorWithWhite:0.2 alpha:0.4] setFill];
CGContextAddPath(cakeContextRef, path);
CGContextDrawPath(cakeContextRef, kCGPathFill);
}
//最后一句,上一塊的結(jié)束角度是下一塊的開始角度
startAngle = endAngle;
}
//此時(shí)不能用以下的方法填充,會(huì)導(dǎo)致餅圖就一種顏色
//CGContextFillPath(contextRef);
}
-(void)setDataArray:(NSArray *)dataArray
{
_dataArray = dataArray;
//重新繪制
[self setNeedsDisplay];
}
這里要說(shuō)明一下,我的數(shù)組是百分比數(shù)組,由數(shù)值轉(zhuǎn)化為百分比的過程我沒有在這里處理。
如何使用view:
self.solidCakeView = [[SSSolidCakeView alloc]init]; self.solidCakeView.dataArray = _dataArray; self.solidCakeView.colorArray = _colorArray; self.solidCakeView.nameArray = _nameArray; self.solidCakeView.cakeCenter = CGPointMake(200, 200); self.solidCakeView.cakeRadius = 100; self.solidCakeView.cakeHeight = 30; self.solidCakeView.xScale = 1; self.solidCakeView.yScale = 0.8; self.solidCakeView.backgroundColor = [UIColor whiteColor]; self.solidCakeView.frame = CGRectMake(0, 0, PhoneScreen_WIDTH-100, PhoneScreen_HEIGHT-20); [self.view addSubview:self.solidCakeView];
3D餅圖如何繪制及使用已經(jīng)用代碼介紹完了,相信看到這大家應(yīng)該也能實(shí)現(xiàn)3D餅圖了。
本文參考了:http://blog.csdn.net/donny_zhang/article/details/9145379 感謝博主!
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)各位iOS開發(fā)者們能有一定的幫助,如果有疑問大家可以留言交流。
相關(guān)文章
iOS開發(fā)實(shí)現(xiàn)HTTPS之cer文件的使用詳解
下面小編就為大家分享一篇iOS開發(fā)實(shí)現(xiàn)HTTPS之cer文件的使用詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2018-01-01
iOS中設(shè)置父視圖透明但內(nèi)容不透明的方法
設(shè)置一定的背景透明會(huì)讓用戶的體驗(yàn)非常不錯(cuò),下面這篇文章就主要跟大家分享了iOS中設(shè)置父視圖透明但內(nèi)容不透明的方法,文中給出了詳細(xì)的示例代碼,需要的朋友們下面來(lái)一起看看吧。2017-05-05
實(shí)例講解iOS應(yīng)用UI開發(fā)之基礎(chǔ)動(dòng)畫的創(chuàng)建
這篇文章主要介紹了iOS應(yīng)用UI開發(fā)之基礎(chǔ)動(dòng)畫的創(chuàng)建,以關(guān)鍵幀動(dòng)畫作為重要知識(shí)點(diǎn)進(jìn)行講解,需要的朋友可以參考下2015-11-11
IOS實(shí)現(xiàn)選擇城市后跳轉(zhuǎn)Tabbar效果
這篇文章主要為大家詳細(xì)介紹了IOS實(shí)現(xiàn)選擇城市后跳轉(zhuǎn)Tabbar效果的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-07-07
使用UITextField限制只可輸入中,英文,數(shù)字的方法
在我們?nèi)粘i_發(fā)中經(jīng)常遇到一些情況,要UITextField只能輸入某一種特定的字符.比如大寫A-Z或者小寫a-z,或者漢字.或者數(shù)字.那么該如何實(shí)現(xiàn)呢,下面通過這篇文章來(lái)看看吧。2016-09-09

