动画Bezier曲线,就像在iPhone屏幕上绘制一样

时间:2016-02-12 12:49:46

标签: ios objective-c animation uibezierpath

我想绘制一条泰姬陵坟墓轮廓的bezier路径。

Q1。我怎么能在XCode中绘制它?我可以很容易地在PS中做到这一点,但我发现在编程方面很难做到特别是获取控制点的坐标。

Q2。此外,当屏幕尺寸变化时,如何固定点的坐标?

Q3。我怎么能像看不见的铅笔画在屏幕上那样动画呢?

3 个答案:

答案 0 :(得分:20)

如何在UIKit中绘制贝塞尔曲线?

创建UIBezierPath对象,然后使用various methods on it to construct your path

我怀疑你最感兴趣的方法是:

例如,像这样的东西会创建一个带有二次曲线的简单贝塞尔曲线:

UIBezierPath* yourPath = [UIBezierPath bezierPath]; // create the bezier path
[yourPath moveToPoint:CGPointMake(100, 100)]; // move to your starting point
[yourPath addQuadCurveToPoint:CGPointMake(300, 500) controlPoint:CGPointMake(500, 350)]; // add a new quad curve to the point

但是,如果您习惯使用Photoshop之类的东西创建路径,那么may be interested in PaintCode可以让您使用“所见即所得”的方法创建贝塞尔路径。

您可以将此UIBezierPath添加到path的{​​{1}}媒体资源中,以便在屏幕上显示。

CAShapeLayer

然后,您可以在形状图层上轻松设置CAShapeLayer* yourShapeLayer = [CAShapeLayer layer]; // create your shape layer yourShapeLayer.frame = CGRectMake(0, 0, 300, 500); // assign it's frame yourShapeLayer.path = yourPath.CGPath; // add your path to the shape layer yourShapeLayer.fillColor = [UIColor clearColor].CGColor; // prevent the shape layer from filling [self.view.layer addSublayer:yourShapeLayer]; // add the shape layer to the view strokeColor属性,以便自定义路径的描边方式。

lineWidth

你应该得到这样的东西:

enter image description here

我怎么能像看不见的铅笔在屏幕上绘制它一样为它设置动画?

您可以轻松创建一个yourShapeLayer.strokeColor = [UIColor redColor].CGColor; // red stroke color yourShapeLayer.lineWidth = 5.0; // 5 point stroke width ,可以为CABasicAnimation的{​​{1}}或strokeStart属性制作动画,以实现您想要的动画效果。

这可能会导致线条“被绘制”到屏幕上的动画效果。

例如,此代码会导致strokeEnd属性动画从CAShapeLayerstrokeEnd,从而产生您想要的效果:

0.0

enter image description here

如何缩放此路径以使用不同大小的屏幕?

我通常喜欢解决此问题的方法是在给定的固定框架中定义路径的点(比如500 x 500点),然后生成基于的比例因子屏幕大小(在您的情况下,您希望缩放到屏幕的宽度)。

所以我们所要做的就是生成比例因子。

1.0

然后,我们只需通过此比例因子将yourShapeLayer.strokeStart = 0.0; // reset stroke start before animating CABasicAnimation* strokeAnim = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; // create animation that changes the strokeEnd property strokeAnim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; // give it a nice timing function strokeAnim.duration = 2.0; // duration of the animation strokeAnim.fromValue = @(0.0); // provide the start value for the animation, wrapped in an NSNumber literal. strokeAnim.toValue = @(1.0); // provide the end value for the animation, wrapped in an NSNumber literal. [yourShapeLayer addAnimation:strokeAnim forKey:@"strokeAnim"]; // add animation to layer 中的所有点加倍。例如,采用我们之前的路径:

CGFloat sf = self.view.frame.size.width/500.0; // The factor to scale the path by

现在,我们所要做的就是在我们的bezier路径点中编程,好像我们总是在500 x 500帧中绘制它(我的点已经很好地适应了它)。

您还需要更改UIBezierPath的大小,使其平方并占据整个屏幕宽度。

UIBezierPath* yourPath = [UIBezierPath bezierPath]; // create the bezier path
[yourPath moveToPoint:CGPointMake(100.0*sf, 100.0*sf)]; // move to your starting point
[yourPath addQuadCurveToPoint:CGPointMake(300.0*sf, 500.0*sf) controlPoint:CGPointMake(500.0*sf, 350.0*sf)];

最后,您希望将CAShapeLayer置于屏幕中心。您可以通过将图层的yourShapeLayer.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.width); 属性设置为视图的CAShapeLayer来轻松完成此操作。

position

现在,您的路径应始终缩放以占据屏幕的宽度。

enter image description here

(我在图层中添加了灰色背景以说明缩放)

完整项目(为方便起见):https://github.com/hamishknight/Drawing-Scaling-Animating-UIBezierPaths

答案 1 :(得分:2)

我在2010年发表了关于此事的博文:Animating the Drawing of a CGPath With CAShapeLayer

它的主旨是:

  • 使用您想要绘制的形状创建UIBezierPathCGPath。使用moveToPoint:addLineToPoint: addCurveToPoint:controlPoint1:controlPoint2:等方法创建形状。
  • 创建CGShapeLayer并指定图层path属性的路径。
  • 将图层添加到视图/图层层次结构中(例如,在视图控制器中:[self.view.layer addSublayer:shapeLayer];)。您还必须为图层指定有效的大小和位置(frame)。
  • 将图层的strokeEnd属性设置为0到1。

答案 2 :(得分:1)

originaluser2发布的答案解决了所有问题。如果要为不同的设备屏幕调整贝塞尔曲线路径,也可以尝试这种方式:

您可以简单地将UIView子类化并自定义其drawRect方法:

  - (void)drawRect: (CGRect)frame
{

    //// Bezier Drawing
UIBezierPath* bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint: CGPointMake(CGRectGetMinX(frame) + 0.23370 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.65441 * CGRectGetHeight(frame))];
[bezierPath addCurveToPoint: CGPointMake(CGRectGetMinX(frame) + 0.49457 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.33088 * CGRectGetHeight(frame)) controlPoint1: CGPointMake(CGRectGetMinX(frame) + 0.23370 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.65441 * CGRectGetHeight(frame)) controlPoint2: CGPointMake(CGRectGetMinX(frame) + 0.35870 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.33088 * CGRectGetHeight(frame))];
[bezierPath addCurveToPoint: CGPointMake(CGRectGetMinX(frame) + 0.77717 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.65441 * CGRectGetHeight(frame)) controlPoint1: CGPointMake(CGRectGetMinX(frame) + 0.63043 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.33088 * CGRectGetHeight(frame)) controlPoint2: CGPointMake(CGRectGetMinX(frame) + 0.77717 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.65441 * CGRectGetHeight(frame))];
[UIColor.blackColor setStroke];
bezierPath.lineWidth = 1;
[bezierPath stroke];

}

第50x50帧:

enter image description here

第100x100帧:

enter image description here

框架100x50

enter image description here

如果发送大小为50x50的帧,则会在大小为50x50的帧中绘制贝塞尔曲线。此代码也会根据收到的帧大小自动调整大小。