前言
最近做手表手環(huán)類app比較多,這種類型的app有個(gè)特點(diǎn)就是最喜歡用圖表去展示數(shù)據(jù)。接到公司項(xiàng)目的時(shí)候看到圖表第一時(shí)間就網(wǎng)上找找有沒有合適的,這樣既省時(shí)又高效。但是搜索一圈之后發(fā)現(xiàn)都沒有找到滿意,所以最后決定還是自己動(dòng)手寫一個(gè)出來,借鑒了UUChart的寫法。
調(diào)用方式
YzcChartView *view = [[YzcChartView alloc] initWithFrame:CGRectMake(10, 100, self.view.frame.size.width, 200)];
view.style = YzcLineGrid;
view.isdrawLine = YES; //網(wǎng)格線
view.isDrawPoint = YES; //圓點(diǎn)
view.isShadow = YES; //陰影填充
view.unit = @"bpm"; //左邊的單位
view.lineColor = [UIColor redColor];
view.pointColor = [UIColor orangeColor];
view.yLabels = @[@"60",@"70",@"140",@"80",@"120",@"140",@"80",@"120",@"140",@"80",@"120",@"80",@"120",@"80",@"120"];
view.xLabels = @[@"0min",@"30min",@"60min",@"90min",@"120min",@"60min",@"90min",@"120min",@"60min",@"90min",@"120min",@"120min",@"60min",@"90min",@"120min"];
[view strokeChart];
[self.scrollView addSubview:view];
代碼實(shí)現(xiàn)
繪畫表格豎線和X軸刻度
- (void)setXLabels:(NSArray *)xLabels
{
_xLabels = xLabels;
CGFloat num = 0;
if (xLabels.count>=20) {
num=20.0;
}else if (xLabels.count<=1){
num=1.0;
}else{
num = xLabels.count;
}
_xLabelWidth = (self.myScrollView.frame.size.width - UUYLabelwidth * 0.5)/(self.style ? 23 : 10);
NSInteger count = xLabels.count > 10 ? xLabels.count : 10;
count = self.style ? 24 : count;
for (int i=0; i<count; i++) {
if (self.style == YzcLineGrid) {
if (i%2 == 0) {
NSString *labelText = xLabels[i];
YzcLabel * label = [[YzcLabel alloc] initWithFrame:CGRectMake(i * _xLabelWidth+UUYLabelwidth*0.5-10, self.frame.size.height - UULabelHeight, _xLabelWidth, UULabelHeight)];
label.text = labelText;
[self.myScrollView addSubview:label];
}
}else{
if (i%6 == 0) {
YzcLabel * label = [[YzcLabel alloc] initWithFrame:CGRectMake(i * _xLabelWidth+UUYLabelwidth*0.5, self.frame.size.height - UULabelHeight, _xLabelWidth*2, UULabelHeight)];
label.text = [NSString stringWithFormat:@"%02d:00",i];
[self.myScrollView addSubview:label];
}
}
}
if (self.style == YzcLineNone) {
//畫底部的點(diǎn)
for (int i=0; i<24; i++) {
[self addPoint:CGPointMake(UUYLabelwidth+i*_xLabelWidth,self.frame.size.height-UULabelHeight-10)];
}
float max = ((count-1)*_xLabelWidth + chartMargin)+_xLabelWidth;
self.myScrollView.contentSize = CGSizeMake(max+10, 0);
}else{
//畫豎線
for (int i=0; i<count; i++) {
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(UUYLabelwidth+i*_xLabelWidth,0)];
[path addLineToPoint:CGPointMake(UUYLabelwidth+i*_xLabelWidth,self.frame.size.height-UULabelHeight-10)];
[path closePath];
shapeLayer.path = path.CGPath;
shapeLayer.strokeColor = self.yLineColor ? self.yLineColor.CGColor : [[[UIColor blackColor] colorWithAlphaComponent:0.1] CGColor];
shapeLayer.fillColor = [[UIColor whiteColor] CGColor];
shapeLayer.lineWidth = 1;
[self.myScrollView.layer addSublayer:shapeLayer];
}
float max = ((count-1)*_xLabelWidth + chartMargin)+_xLabelWidth;
if (self.myScrollView.frame.size.width < max-10) {
self.myScrollView.contentSize = CGSizeMake(max+10, 0);
}
}
}
繪畫橫線和Y軸的刻度
- (void)setYLabels:(NSArray *)yLabels
{
_yLabels = yLabels;
_xLabelWidth = (self.myScrollView.frame.size.width - UUYLabelwidth * 0.5)/(self.style ? 23 : 10);
CGFloat _yValueMax = [[self.yLabels valueForKeyPath:@"@max.floatValue"] floatValue];
CGFloat _yValueMin = [[self.yLabels valueForKeyPath:@"@min.floatValue"] floatValue];
float level = (_yValueMax-_yValueMin) /3;
CGFloat chartCavanHeight = self.frame.size.height - UULabelHeight*3;
CGFloat levelHeight = chartCavanHeight /3;
for (int i=0; i<4; i++) {
YzcLabel * label = [[YzcLabel alloc] initWithFrame:CGRectMake(0,chartCavanHeight - i * levelHeight, UUYLabelwidth+20, UULabelHeight)];
label.text = [NSString stringWithFormat:@"%d%@",(int)(level * i+_yValueMin),self.unit ? self.unit : @""];
[self addSubview:label];
}
if (self.style == YzcLineGrid) {
//畫橫線
for (int i=0; i<4; i++) {
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(20,UULabelHeight+i*levelHeight)];
[path addLineToPoint:CGPointMake(self.frame.size.width,UULabelHeight+i*levelHeight)];
[path closePath];
shapeLayer.path = path.CGPath;
shapeLayer.strokeColor = self.xlineColor ? self.xlineColor.CGColor :[[[UIColor blackColor] colorWithAlphaComponent:0.1] CGColor];
shapeLayer.fillColor = [[UIColor whiteColor] CGColor];
shapeLayer.lineWidth = 1;
[self.layer insertSublayer:shapeLayer atIndex:0];
}
float max = (([yLabels count]-1)*_xLabelWidth + chartMargin)+_xLabelWidth;
if (self.myScrollView.frame.size.width < max-10) {
self.myScrollView.contentSize = CGSizeMake(max+10, 0);
}
}
}
漸變圖層的填充方法
漸變圖層的顏色設(shè)置成折線的顏色一樣,然后調(diào)顏色透明度即可,這樣看起來就會(huì)有漸變效果,最后加上動(dòng)畫。
/**
添加漸變圖層
*/
- (void)addGradientLayer:(UIBezierPath *)bezier1
{
CAShapeLayer *shadeLayer = [CAShapeLayer layer];
shadeLayer.path = bezier1.CGPath;
shadeLayer.fillColor = [UIColor greenColor].CGColor;
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = CGRectMake(5, 0, 0, self.myScrollView.bounds.size.height-20);
gradientLayer.cornerRadius = 5;
gradientLayer.masksToBounds = YES;
gradientLayer.colors = @[(__bridge id)[self.lineColor colorWithAlphaComponent:0.4].CGColor,(__bridge id)[self.lineColor colorWithAlphaComponent:0.0].CGColor]; //如果需要調(diào)圖層顏色,只需要修改這里即可
gradientLayer.locations = @[@(0.1f),@(1.0f)];
gradientLayer.startPoint = CGPointMake(0, 0);
gradientLayer.endPoint = CGPointMake(1, 1);
CALayer *baseLayer = [CALayer layer];
[baseLayer addSublayer:gradientLayer];
[baseLayer setMask:shadeLayer];
[self.myScrollView.layer insertSublayer:baseLayer atIndex:0];
CABasicAnimation *anmi1 = [CABasicAnimation animation];
anmi1.keyPath = @"bounds";
anmi1.duration = _yLabels.count*0.4;
anmi1.toValue = [NSValue valueWithCGRect:CGRectMake(5, 0, 2*self.lastPoint.x, self.myScrollView.bounds.size.height-20)];
anmi1.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
anmi1.fillMode = kCAFillModeForwards;
anmi1.autoreverses = NO;
anmi1.removedOnCompletion = NO;
[gradientLayer addAnimation:anmi1 forKey:@"bounds"];
}
最后就是繪畫數(shù)據(jù)
- (void)strokeChart
{
BOOL isShowMaxAndMinPoint = YES;
NSInteger maxValue = [[_yLabels valueForKeyPath:@"@max.intValue"] integerValue];
NSInteger minValue = [[_yLabels valueForKeyPath:@"@min.intValue"] integerValue];
//劃線
CAShapeLayer *_chartLine = [CAShapeLayer layer];
_chartLine.lineCap = kCALineCapRound; //設(shè)置線條拐角帽的樣式
_chartLine.lineJoin = kCALineJoinRound; //設(shè)置兩條線連結(jié)點(diǎn)的樣式
_chartLine.fillColor = [[UIColor clearColor] CGColor];
_chartLine.lineWidth = 2.0;
_chartLine.strokeEnd = 0.0;
[self.myScrollView.layer addSublayer:_chartLine];
//線
UIBezierPath *progressline = [UIBezierPath bezierPath];
CGFloat firstValue = [[_yLabels objectAtIndex:0] floatValue];
CGFloat xPosition = UUYLabelwidth;
CGFloat chartCavanHeight = self.frame.size.height - UULabelHeight*3;
//第一個(gè)點(diǎn)
float grade = ((float)firstValue-minValue) / ((float)maxValue-minValue);
if (isnan(grade)) {
grade = 0;
}
CGPoint firstPoint = CGPointMake(xPosition, chartCavanHeight - grade * chartCavanHeight+UULabelHeight);
[progressline moveToPoint:firstPoint];
[progressline setLineWidth:2.0];
[progressline setLineCapStyle:kCGLineCapRound];
[progressline setLineJoinStyle:kCGLineJoinRound];
//遮罩層形狀
UIBezierPath *bezier1 = [UIBezierPath bezierPath];
bezier1.lineCapStyle = kCGLineCapRound;
bezier1.lineJoinStyle = kCGLineJoinMiter;
[bezier1 moveToPoint:firstPoint];
self.originPoint = firstPoint; //記錄原點(diǎn)
NSInteger index = 0;
for (NSString * valueString in _yLabels) {
float grade =([valueString floatValue] - minValue) / ((float)maxValue-minValue);
if (isnan(grade)) {
grade = 0;
}
CGPoint point = CGPointMake(xPosition+index*_xLabelWidth, chartCavanHeight - grade * chartCavanHeight+UULabelHeight);
if (index != 0) {
[progressline addCurveToPoint:point controlPoint1:CGPointMake((point.x+self.prePoint.x)/2, self.prePoint.y) controlPoint2:CGPointMake((point.x+self.prePoint.x)/2, point.y)];
[progressline moveToPoint:point];
[bezier1 addCurveToPoint:point controlPoint1:CGPointMake((point.x+self.prePoint.x)/2, self.prePoint.y) controlPoint2:CGPointMake((point.x+self.prePoint.x)/2, point.y)];
}
if (index == _yLabels.count-1) {
self.lastPoint = point; //記錄最后一個(gè)點(diǎn)
}
if (self.isDrawPoint) {
[self addPoint:point
index:index
isShow:isShowMaxAndMinPoint
value:[valueString floatValue]];
}
index += 1;
self.prePoint = point;
}
if (self.isdrawLine) {
_chartLine.path = progressline.CGPath;
_chartLine.strokeColor = self.lineColor ? self.lineColor.CGColor : [UIColor greenColor].CGColor;
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
pathAnimation.duration = _yLabels.count*0.4;
pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
pathAnimation.toValue = [NSNumber numberWithFloat:1.0f];
pathAnimation.autoreverses = NO;
[_chartLine addAnimation:pathAnimation forKey:@"strokeEndAnimation"];
_chartLine.strokeEnd = 1.0;
if (self.isShadow) {
[bezier1 addLineToPoint:CGPointMake(self.lastPoint.x, self.frame.size.height - UULabelHeight*2)];
[bezier1 addLineToPoint:CGPointMake(self.originPoint.x, self.frame.size.height - UULabelHeight*2)];
[bezier1 addLineToPoint:self.originPoint];
[self addGradientLayer:bezier1];
}
}
}
最后附上完整demo地址:https://github.com/Yzc-jason/YzcChart
簡書初筆,請(qǐng)多多指教,歡迎發(fā)問。如果有幸你也用上了,記得點(diǎn)個(gè)star哈。