我为我的公司建造了这个:https://github.com/busycm/BZYStrokeTimer并且在建造过程中,我注意到了一个有趣的"错误"在使用UIBezierPath
时,我似乎无法缓解。在动画开始时,路径向前跳跃一定数量的像素(或者向后跳,取决于它是否逆时针)而不是以平滑的增量动画开始。而我发现真正有趣的是,向前跳跃的路径实际上是CAShaperLayer
的线宽值。
例如,如果我的贝塞尔曲线路径从CGRectGetMidX(self.bounds)
开始并且线路为35,则动画实际上从CGRectGetMidX(self.bounds)+35
开始,线宽越大,跳跃越明显。有没有办法摆脱它,以便路径将从起点平滑地动画出来?
这是第一帧的图片。这是动画开始后立即看起来的样子。
然后当我恢复动画并再次暂停时,移动的距离大约是你在图片中看到的距离的1/100。
这是我的bezier路径代码:
- (UIBezierPath *)generatePathWithXInset:(CGFloat)dx withYInset:(CGFloat)dy clockWise:(BOOL)clockwise{
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(CGRectGetMidX(self.bounds)+dx/2, dy/2)];
[path addLineToPoint:CGPointMake(CGRectGetMaxX(self.bounds)-dx/2, dy/2)];
[path addLineToPoint:CGPointMake(CGRectGetMaxX(self.bounds)-dx/2, CGRectGetMaxY(self.bounds)-dy/2)];
[path addLineToPoint:CGPointMake(dx/2, CGRectGetMaxY(self.bounds)-dy/2)];
[path addLineToPoint:CGPointMake(dx/2, dy/2)];
[path closePath];
return clockwise ? path : [path bezierPathByReversingPath];
}
这是动画代码:
CABasicAnimation *wind = [self generateAnimationWithDuration:self.duration == 0 ? kDefaultDuration : self.duration fromValue:@(self.shapeLayer.strokeStart) toValue:@(self.shapeLayer.strokeEnd) withKeypath:keypath withFillMode:kCAFillModeForwards];
wind.timingFunction = [CAMediaTimingFunction functionWithName:self.timingFunction];
wind.removedOnCompletion = NO;
self.shapeLayer.path = [self generatePathWithXInset:self.lineWidth withYInset:self.lineWidth clockWise:self.clockwise].CGPath;
[self.shapeLayer addAnimation:wind forKey:@"strokeEndAnimation"];
以下是我如何构建CAShapeLayer
。
- (CAShapeLayer *)shapeLayer {
return !_shapeLayer ? _shapeLayer = ({
CAShapeLayer *layer = [CAShapeLayer layer];
layer.lineWidth = kDefaultLineWidth;
layer.fillColor = UIColor.clearColor.CGColor;
layer.strokeColor = [UIColor blackColor].CGColor;
layer.lineCap = kCALineCapSquare;
layer.frame = self.bounds;
layer.strokeStart = 0;
layer.strokeEnd = 1;
layer;
}) : _shapeLayer;
}
答案 0 :(得分:3)
我认为这里发生的事情是,在动画的这个框架中,您绘制的是由单个点组成的线条。由于线条具有与之关联的厚度,并且线条类型为kCALineCapSquare
,因此该线条将被渲染为高度和宽度等于线宽的正方形。
您可以将其想象为使用方形标记绘制线条,并且您将拖动标记的中点以使其穿过您指定的曲线中的每个点。对于该行中的第一个点,就好像标记在该点触及,留下一个正方形。
Here's可视化表示不同的线帽类型,有望使其更直观。您应该将线帽样式更改为kCALineCapButt
。
<强>旁注:强> 在进行此更改后,在此代码行中
[path moveToPoint:CGPointMake(CGRectGetMidX(self.bounds)+dx/2, dy/2)];
你可能不必再将x
坐标偏移dx/2
了。