_panel.layer.cornerRadius = 5;
-(void)animateLinesWithColor:(CGColorRef)lineColor andLineWidth:(CGFloat)lineWidth animationDuration:(CGFloat)duration { }
CAShapeLayer* animateLayer = [CAShapeLayer layer]; animateLayer.lineCap = kCALineCapRound;// animateLayer.lineJoin = kCALineJoinBevel;// animateLayer.fillColor = [[UIColor clearColor] CGColor];// animateLayer.lineWidth = lineWidth; animateLayer.strokeEnd = 0.0;
UIBezierPath* path = [UIBezierPath new]; [path setLineWidth:1.0]; [path setLineCapStyle:kCGLineCapRound]; [path setLineJoinStyle:kCGLineJoinRound];
CGRect bounds = self.layer.bounds;// CGFloat radius = self.layer.cornerRadius;// CGPoint zeroPoint = bounds.origin; // BOOL isRounded = radius>0; if(isRounded) { zeroPoint.x = bounds.origin.x+radius; // - , , . } [path moveToPoint:zeroPoint];// // 4 . CGPoint nextPoint = CGPointMake(bounds.size.width, 0); if(isRounded) { nextPoint.x-=radius; } [path addLineToPoint:nextPoint]; if(isRounded) { [path addArcWithCenter:CGPointMake(nextPoint.x, nextPoint.y+radius) radius:radius startAngle:-M_PI_2 endAngle:0 clockwise:YES];// - . } // nextPoint = CGPointMake(bounds.size.width, bounds.size.height); if(isRounded) { nextPoint.y-=radius; } [path addLineToPoint:nextPoint]; if (isRounded) { [path addArcWithCenter:CGPointMake(nextPoint.x-radius, nextPoint.y) radius:radius startAngle:0 endAngle:M_PI_2 clockwise:YES]; } // nextPoint = CGPointMake(0, bounds.size.height); if(isRounded) { nextPoint.x +=radius; } [path addLineToPoint:nextPoint]; if (isRounded) { [path addArcWithCenter:CGPointMake(nextPoint.x, nextPoint.y-radius) radius:radius startAngle:M_PI_2 endAngle:M_PI clockwise:YES]; } // nextPoint = CGPointMake(0, 0); if(isRounded) { nextPoint.y +=radius; } [path addLineToPoint:nextPoint]; if (isRounded) { [path addArcWithCenter:CGPointMake(nextPoint.x+radius, nextPoint.y) radius:radius startAngle:M_PI endAngle:-M_PI_2 clockwise:YES]; }
animateLayer.path = path.CGPath; animateLayer.strokeColor = lineColor;
[self.layer addSublayer:animateLayer];
_panel.layer.cornerRadius = 5; [_panel animateLinesWithColor:[UIColor redColor].CGColor andLineWidth:2 animationDuration:5];
Here you need a small digression.
When you draw in Path (UIPath, CGPath) segments, circles and other primitives - they all have a beginning and an end. StrokeEnd at CAShapeLayer means to what place it is worth drawing this line.
StrokeStart, in turn, indicates where to start drawing a line. The value should lie in the range 0.0 - 1.0
For example:
animateLayer.strokeEnd = 0.0;
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; pathAnimation.duration = duration; pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f]; pathAnimation.toValue = [NSNumber numberWithFloat:1.0f]; pathAnimation.autoreverses = NO; [animateLayer addAnimation:pathAnimation forKey:@"strokeEndAnimation"]; animateLayer.strokeEnd = 1.0;
[path addCurveToPoint:controlPoint1:controlPoint2:];
@interface LinesCurvePoints : NSObject @property(nonatomic,assign)CGPoint controlPoint1; @property(nonatomic,assign)CGPoint controlPoint2; +(instancetype)curvePoints:(CGPoint)point1 point2:(CGPoint)point2; @end @implementation LinesCurvePoints +(instancetype)curvePoints:(CGPoint)point1 point2:(CGPoint)point2 { LinesCurvePoints* point = [LinesCurvePoints new]; point.controlPoint1 = point1; point.controlPoint1 = point2; return point; } @end
-(void)animateLinesWithColor:(CGColorRef)lineColor andLineWidth:(CGFloat)lineWidth startPoint:(CGPoint)startFromPoint rollToStroke:(CGFloat)rollToStroke curveControlPoints:(NSArray<LinesCurvePoints*>*)curvePoints animationDuration:(CGFloat)duration
[path moveToPoint:startFromPoint]; long c = curvePoints.count; for (long i =1; i<=c; i++) { float nX = startFromPoint.x + (zeroPoint.x - startFromPoint.x)/(c)*i; float nY = startFromPoint.y +(zeroPoint.y - startFromPoint.y)/(c)*i; LinesCurvePoints* point = curvePoints[i-1]; [path addCurveToPoint:CGPointMake(nX, nY) controlPoint1:CGPointMake(nX+point.controlPoint1.x,nY+point.controlPoint1.y) controlPoint2:CGPointMake(nX+ point.controlPoint2.y,nY+ point.controlPoint2.y)]; }
pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeStart"]; pathAnimation.duration = duration*1.2; pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]; pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f]; pathAnimation.toValue = [NSNumber numberWithFloat:rollToStroke]; pathAnimation.autoreverses = NO; [animateLayer addAnimation:pathAnimation forKey:@"strokeStartAnimation"]; animateLayer.strokeStart = rollToStroke;
-(void)animateLinesWithColor:(CGColorRef)lineColor andLineWidth:(CGFloat)lineWidth startPoint:(CGPoint)startFromPoint rollToStroke:(CGFloat)rollToStroke curveControlPoints:(NSArray<LinesCurvePoints*>*)curvePoints animationDuration:(CGFloat)duration { CAShapeLayer* animateLayer = [CAShapeLayer layer]; animateLayer.lineCap = kCALineCapRound; animateLayer.lineJoin = kCALineJoinBevel; animateLayer.fillColor = [[UIColor clearColor] CGColor]; animateLayer.lineWidth = lineWidth; animateLayer.strokeEnd = 0.0; UIBezierPath* path = [UIBezierPath new]; [path setLineWidth:1.0]; [path setLineCapStyle:kCGLineCapRound]; [path setLineJoinStyle:kCGLineJoinRound]; CGRect bounds = self.layer.bounds; CGFloat radius = self.layer.cornerRadius; CGPoint zeroPoint = bounds.origin; BOOL isRounded = radius>0; if(isRounded) { zeroPoint.x = bounds.origin.x+radius; } [path moveToPoint:startFromPoint]; long c = curvePoints.count; for (long i =1; i<=c; i++) { float nX = startFromPoint.x + (zeroPoint.x - startFromPoint.x)/(c)*i; float nY = startFromPoint.y +(zeroPoint.y - startFromPoint.y)/(c)*i; LinesCurvePoints* point = curvePoints[i-1]; [path addCurveToPoint:CGPointMake(nX, nY) controlPoint1:CGPointMake(nX+point.controlPoint1.x,nY+point.controlPoint1.y) controlPoint2:CGPointMake(nX+ point.controlPoint2.y,nY+ point.controlPoint2.y)]; } [path moveToPoint:zeroPoint]; CGPoint nextPoint = CGPointMake(bounds.size.width, 0); if(isRounded) { nextPoint.x-=radius; } [path addLineToPoint:nextPoint]; if(isRounded) { [path addArcWithCenter:CGPointMake(nextPoint.x, nextPoint.y+radius) radius:radius startAngle:-M_PI_2 endAngle:0 clockwise:YES]; } nextPoint = CGPointMake(bounds.size.width, bounds.size.height); if(isRounded) { nextPoint.y-=radius; } [path addLineToPoint:nextPoint]; if (isRounded) { [path addArcWithCenter:CGPointMake(nextPoint.x-radius, nextPoint.y) radius:radius startAngle:0 endAngle:M_PI_2 clockwise:YES]; } nextPoint = CGPointMake(0, bounds.size.height); if(isRounded) { nextPoint.x +=radius; } [path addLineToPoint:nextPoint]; if (isRounded) { [path addArcWithCenter:CGPointMake(nextPoint.x, nextPoint.y-radius) radius:radius startAngle:M_PI_2 endAngle:M_PI clockwise:YES]; } nextPoint = CGPointMake(0, 0); if(isRounded) { nextPoint.y +=radius; } [path addLineToPoint:nextPoint]; if (isRounded) { [path addArcWithCenter:CGPointMake(nextPoint.x+radius, nextPoint.y) radius:radius startAngle:M_PI endAngle:-M_PI_2 clockwise:YES]; } animateLayer.path = path.CGPath; animateLayer.strokeColor = lineColor; [self.layer addSublayer:animateLayer]; CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; pathAnimation.duration = duration; pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f]; pathAnimation.toValue = [NSNumber numberWithFloat:1.0f]; pathAnimation.autoreverses = NO; [animateLayer addAnimation:pathAnimation forKey:@"strokeEndAnimation"]; animateLayer.strokeEnd = 1.0; pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeStart"]; pathAnimation.duration = duration*1.2; pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]; pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f]; pathAnimation.toValue = [NSNumber numberWithFloat:rollToStroke]; pathAnimation.autoreverses = NO; [animateLayer addAnimation:pathAnimation forKey:@"strokeStartAnimation"]; animateLayer.strokeStart = rollToStroke; }
[_panel animateLinesWithColor:[UIColor redColor].CGColor andLineWidth:2 startPoint:CGPointMake(100, -200) rollToStroke:0.25 curveControlPoints:@[ [LinesCurvePoints curvePoints:CGPointMake(-50, -2) point2:CGPointMake(60, 5)], [LinesCurvePoints curvePoints:CGPointMake(-60, 10) point2:CGPointMake(100, 5)] ] animationDuration:2 ];
Source: https://habr.com/ru/post/318716/