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

来源:互联网 发布:sql select语句 包含 编辑:程序博客网 时间:2024/06/05 15:27
一.动态折线图效果图

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];
   CGFloatrowSpacing =_heightGrid;
   CGFloatcolumnSpacing =_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{
   CGFloatxValue = [data[JHChartViewX]floatValue];
   CGFloatyValue = [data[JHChartViewY]floatValue];
   //x坐标等于value*宽度
   //y坐标等于value/最大值*y高度
   CGPointpoint =CGPointMake(_YLabelWidth+ xValue *(_widthGrid+_widthLine),_YunitLabelHeight+(1-yValue/_maxY)*_yBackLine.frame.size.height);
   returnpoint;
   
}
/**
 生成坐标点
 */
-(void)_creatPoint{
   _pointData= @[].mutableCopy;
   for(NSDictionary*dictin _valueData) {
//转换成当前坐标点
       CGPointpoint = [self_changeValueToPoint:dict];
        [_pointDataaddObject:[NSValuevalueWithCGPoint:point]];
    }
   CGFloatsum = 0;
   //计算总长度
   for(inti =0; i<_pointData.count-1; i++) {
     CGPointp1 = [_pointData[i]CGPointValue];
     CGPointp2 = [_pointData[i+1]CGPointValue];
       CGFloattemp =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];
   CGPointfirstPoint = [_pointData[0]CGPointValue];
   CGPointlastPoint = [_pointData[_pointData.count-1]CGPointValue];
    [pathmoveToPoint:firstPoint];
    [backPathmoveToPoint:CGPointMake(firstPoint.x,_yBackLine.frame.size.height+_YunitLabelHeight)];
   for(NSValue*pointValuein_pointData) {
       CGPointpoint = [pointValueCGPointValue];
       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;
//背景移动遮罩
   CGFloatlineWidth =_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;
       //动画时间
       CGFloatduration =_drawAnimationDuration*(_sumLineWidth/_yReplicatorLayer.frame.size.width);
       //进度程度
       CGFloatprogress =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;
   //动画时间
   CGFloatduration =_animationTime;
   //进度程度
   CGFloatprogress =_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);
        }];
    });