iOS绘图CALayer、UIBezierPath运用(边框、填充、复制、渐变)

一.动态折线图效果图


1.首先绘制网格和坐标CAReplicatorLayer
   //添加网格图层
   //网格列线
   CAReplicatorLayer *rowReplicatorLayer = [CAReplicatorLayernew];
   _xReplicatorLayer = rowReplicatorLayer;
    rowReplicatorLayer.position= CGPointMake(0,0);
   CALayer *rowBackLine = [CALayernew];
   _xBackLine = rowBackLine;
    [rowReplicatorLayeraddSublayer:rowBackLine];
    [mainView.layeraddSublayer:rowReplicatorLayer];
   //网格横线
   CAReplicatorLayer *columnReplicatorLayer = [CAReplicatorLayernew];
   _yReplicatorLayer = columnReplicatorLayer;
    columnReplicatorLayer.position= CGPointMake(0,0);
   CALayer *columnBackLine = [CALayernew];
   _yBackLine = columnBackLine;
    [columnReplicatorLayeraddSublayer:columnBackLine];
    [mainView.layeraddSublayer:columnReplicatorLayer];

    //图层绘制动画
    [CATransactionbegin];
    [CATransactionsetAnimationDuration:0];
   CGFloat rowSpacing = _heightGrid;
   CGFloat columnSpacing = _widthGrid;
   //坐标轴这里我简单的使用label循环创建
   _XLabelView.frame= CGRectMake(_YLabelWidth-_widthGrid/2,_mainView.frame.size.height-_XLabelHeight,_mainView.frame.size.width-_YLabelWidth,_XLabelHeight);
   _YLabelView.frame= CGRectMake(0,0-_heightGrid/2+_YunitLabelHeight,_YLabelWidth,_mainView.frame.size.height-_XLabelHeight);
   //图层复制(设置复制的数量)
   _xReplicatorLayer.instanceCount= _numberY+1;
   _yReplicatorLayer.instanceCount= _valueData.count;
   
   _xReplicatorLayer.instanceTransform= CATransform3DMakeTranslation(0, rowSpacing + _widthLine,0);
   _yReplicatorLayer.instanceTransform= CATransform3DMakeTranslation(columnSpacing +_widthLine,0,0);
   //设置图层大小
   _yReplicatorLayer.frame= _xReplicatorLayer.frame= CGRectMake(_YLabelWidth,_YunitLabelHeight,_mainView.frame.size.width-_YLabelWidth-_spaceWidth,_mainView.frame.size.height-_XLabelHeight-_YunitLabelHeight);
   
   _yBackLine.frame= CGRectMake(0,0,_widthLine,_yReplicatorLayer.frame.size.height);
   _xBackLine.frame= CGRectMake(0,0,_yReplicatorLayer.frame.size.width,_widthLine);
[CATransactioncommit];

2.绘制曲线和折点
   //曲线
   _curveLineLayer.strokeColor= _curveLineColor.CGColor;
   _curveLineLayer.lineWidth= _curveLineWidth;

   CAShapeLayer *curveLineLayer = [CAShapeLayernew];
   _curveLineLayer = curveLineLayer;
    curveLineLayer.fillColor= nil;
    curveLineLayer.lineJoin= kCALineJoinRound;
    [mainView.layeraddSublayer:curveLineLayer];
/**
 将数值转换成坐标
 */
-(CGPoint)_changeValueToPoint:(NSDictionary*)data{
   CGFloat xValue = [data[JHChartViewX]floatValue];
   CGFloat yValue = [data[JHChartViewY]floatValue];
   //x坐标等于value*宽度
   //y坐标等于value/最大值*y高度
   CGPoint point = CGPointMake(_YLabelWidth+ xValue *(_widthGrid+ _widthLine),_YunitLabelHeight+(1-yValue/_maxY)*_yBackLine.frame.size.height);
   return point;
   
}
/**
 生成坐标点
 */
-(void)_creatPoint{
   _pointData = @[].mutableCopy;
   for (NSDictionary*dict in _valueData) {
//转换成当前坐标点
       CGPoint point = [self_changeValueToPoint:dict];
        [_pointDataaddObject:[NSValuevalueWithCGPoint:point]];
    }
   CGFloat sum = 0;
   //计算总长度
   for (inti = 0; i<_pointData.count-1; i++) {
     CGPoint p1 = [_pointData[i]CGPointValue];
     CGPoint p2 = [_pointData[i+1]CGPointValue];
       CGFloat temp = sqrt(pow((p1.x-p2.x),2)+pow((p1.y-p2.y),2));
        sum += temp;
    }
   _sumLineWidth = sum;
}
/**
 生成路径
 */
-(void)_creatPath{
 
    [self_creatPoint];
   UIBezierPath * path = [UIBezierPathbezierPath];
   UIBezierPath *backPath = [UIBezierPathbezierPath];
   CGPoint firstPoint = [_pointData[0]CGPointValue];
   CGPoint lastPoint = [_pointData[_pointData.count- 1]CGPointValue];
    [pathmoveToPoint:firstPoint];
    [backPathmoveToPoint:CGPointMake(firstPoint.x,_yBackLine.frame.size.height+_YunitLabelHeight)];
   for (NSValue*pointValuein _pointData) {
       CGPoint point = [pointValue CGPointValue];
       if (pointValue ==_pointData[0]) {
            [backPathaddLineToPoint:point];
           continue;
        }
        [backPathaddLineToPoint:point];
        [pathaddLineToPoint:point];
    }
    [backPathaddLineToPoint:CGPointMake(lastPoint.x,_yBackLine.frame.size.height+_YunitLabelHeight)];
   _path = path;
//背景路径
   _backPath = backPath;
   
}
/**
 绘制坐标点
 
 @param point坐标点
 @param index标记tag
 */
- (void)drawPoint:(CGPoint)point withIndex:(NSInteger)index{
}

3.绘制背景
//封闭阴影
   CAShapeLayer * backLayer = [CAShapeLayernew];
   _backLayer = backLayer;
    [mainView.layeraddSublayer:backLayer];
   
   CAShapeLayer *progressLayer = [CAShapeLayerlayer];
   _progressLayer = progressLayer;
    [_backLayersetMask:progressLayer];
   //背景
   _backLayer.fillColor= _fillLayerBackgroundColor.CGColor;
   _backLayer.hidden= _fillLayerHidden;
   //背景路劲
   _backLayer.path= _backPath.CGPath;
//背景移动遮罩
   CGFloat lineWidth = _yReplicatorLayer.frame.size.height+_YunitLabelHeight;
   _progressLayer.lineWidth= lineWidth*2;
   _progressLayer.lineCap= kCALineCapSquare;
   _progressLayer.strokeColor= [UIColorwhiteColor].CGColor;
   //将路径填充颜色设置为透明
   _progressLayer.fillColor= [UIColorredColor].CGColor;
4.添加动画效果
    4.1曲线绘制动画
CABasicAnimation*pointAnim = [CABasicAnimationanimationWithKeyPath:@"strokeEnd"];
        pointAnim.fromValue= @0.0;
        pointAnim.toValue= @1.0;
        pointAnim.duration= _drawAnimationDuration;
        [_curveLineLayeraddAnimation:pointAnimforKey:@"drawLine”];

#warning 背景是默认全部填充的,无法像曲线一样移动,故采用setMask:方法,给它加上一个遮罩。利用遮罩的绘制动画,模拟出背景的动画
 //图层直线的轨迹
       UIBezierPath *path = [UIBezierPathbezierPath];
#warning起始点似乎有问题
        [pathmoveToPoint:CGPointMake(-_widthGrid*2,0)];
        [pathaddLineToPoint:CGPointMake(_yReplicatorLayer.frame.size.width,0)];
       _progressLayer.path= path.CGPath;
       _progressLayer.strokeEnd= 0.0;
       //动画时间
       CGFloat duration = _drawAnimationDuration*(_sumLineWidth/_yReplicatorLayer.frame.size.width);
       //进度程度
       CGFloat progress = 1.0;
       //strokeEnd 动画到某个点结束
       CABasicAnimation *animate = [CABasicAnimationanimationWithKeyPath:@"strokeEnd"];
        animate.removedOnCompletion= NO;
        animate.fillMode= kCAFillModeForwards;
        animate.duration= duration;
        animate.fromValue= @0.0;
        animate.toValue= @(progress);
       //为图层添加动画
        [_progressLayeraddAnimation:animateforKey:@"drawProgress”];
二.动态渐变色百分比移动图效果图
效果图

1.绘制渐变色曲线CAGradientLayer
//将渐变图层添加到animationView的图层上
    [self.animationView.layeraddSublayer:self.gradientLayer];
    [self.gradientLayeraddSublayer:self.gradientColorLayer];
_gradientLayer= [CALayerlayer];
_gradientColorLayer= [CAGradientLayerlayer];
 _gradientLayer.frame= CGRectMake(0,0,_animationView.frame.size.width,_animationView.frame.size.height);
   _gradientColorLayer.frame= CGRectMake(0,0,_animationView.frame.size.width,_animationView.frame.size.height);
   _gradientColorLayer.cornerRadius= _gradientLayer.frame.size.height/2;
        [_gradientColorLayersetColors:[NSArrayarrayWithObjects:(id)_startColor.CGColor,(id)_endColor.CGColor,nil]];
       //渐变方向水平
        [_gradientColorLayersetStartPoint:CGPointMake(0,1)];
2.添加蒙版CAShapeLayer
CGFloatlineWidth =progressHeight;
       
       _progressLayer = [CAShapeLayerlayer];
       
       _progressLayer.lineWidth= lineWidth*2;
       _progressLayer.lineCap= kCALineCapSquare;
       _progressLayer.strokeColor= [UIColorwhiteColor].CGColor;
       //将路径填充颜色设置为透明
       _progressLayer.fillColor= [UIColorclearColor].CGColor;
 //用progressLayer来截取渐变层
    [self.gradientLayersetMask:self.progressLayer];
3.绘制百分比向下箭头Label
/**
 绘制向下的三角形(这里的路径超出了Label,当然我们只要不截取超出部分就行了,不用管原始Label中的文字是否居中)
 */
-(void)drawTriangle{
   //圆角矩形
   UIBezierPath *path = [UIBezierPathbezierPathWithRoundedRect:_labPercent.framecornerRadius:3];
   //三角形
   UIBezierPath *trianglePath = [[UIBezierPathalloc]init];
    [trianglePathmoveToPoint:CGPointMake(_percentView.frame.size.width/2-2,_percentView.frame.size.height-5)];;
    [trianglePathaddLineToPoint:CGPointMake(_percentView.frame.size.width/2,_percentView.frame.size.height)];
    [trianglePathaddLineToPoint:CGPointMake(_percentView.frame.size.width/2+2,_percentView.frame.size.height-5)];
   //扩展绘制路径
    [pathappendPath:trianglePath];
   CAShapeLayer *fillLayer = [CAShapeLayerlayer];
    fillLayer.path= path.CGPath;
    fillLayer.fillColor= kBaseColor.CGColor;
 #warning必须将他添加到最下一层,否则会遮挡其他图层
//    [_labPercent.layer addSublayer:fillLayer];
    [_labPercent.layerinsertSublayer:fillLayeratIndex:0];
}
4.动画
//图层直线的轨迹
   UIBezierPath *path = [UIBezierPathbezierPath];
    [pathmoveToPoint:CGPointMake(0,0)];
    [pathaddLineToPoint:CGPointMake(_animationView.frame.size.width,0)];
   _progressLayer.path= path.CGPath;

   self.progressLayer.strokeEnd= 0.0;
   //动画时间
   CGFloat duration = _animationTime;
   //进度程度
   CGFloat progress = _percent;
   //strokeEnd 动画到某个点结束
   CABasicAnimation *animate = [CABasicAnimationanimationWithKeyPath:@"strokeEnd"];
    animate.removedOnCompletion= NO;
    animate.fillMode= kCAFillModeForwards;
    animate.duration= duration;
    animate.fromValue= @0.0;
#warning存在偏差,目前不知道原因
    animate.toValue= @(progress-0.02);
   //为图层添加动画
    [self.progressLayeraddAnimation:animateforKey:@"anim1"];
   
   //百分比标签动画(iOS 10在layoutSubView中失效???)
    _percentView.center= CGPointMake(0,_percentView.center.y);
#warning此处使用延迟,使动画生效了
   dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01* NSEC_PER_SEC)),dispatch_get_main_queue(), ^{
        [UIViewanimateWithDuration:_animationTimeanimations:^{
           
           _percentView.center= CGPointMake(self.frame.size.width*_percent,_percentView.center.y);
        }];
    });
--------------------- 
作者:Jneth 
来源:CSDN 
原文:https://blog.csdn.net/u010008647/article/details/78214366 
版权声明:本文为博主原创文章,转载请附上博文链接!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值