且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2022-12-19 17:08:35

如何在 UIKit ?



创建 UIBezierPath 对象,然后使用






我怎么能动画它就好像一只隐形铅笔在屏幕上绘制它一样?



你可以轻松创建一个可以动画的 CABasicAnimation strokeStart strokeEnd 属性 CAShapeLayer 以便实现你想要的动画。



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



例如,此代码将导致 strokeEnd 属性从 0.0 设置为 1.0 ,创造您想要的效果:

  yourShapeLayer.strokeStart = 0.0 ; //在设置动画之前重置笔画开始

CABasicAnimation * strokeAnim = [CABasicAnimation animationWithKeyPath:@strokeEnd]; //创建更改strokeEnd属性的动画
strokeAnim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; //给它一个很好的计时函数
strokeAnim.duration = 2.0; //动画的持续时间
strokeAnim.fromValue = @(0.0); //提供动画的起始值,包含在NSNumber文字中。
strokeAnim.toValue = @(1.0); //提供动画的结束值,包含在NSNumber文字中。

[yourShapeLayer addAnimation:strokeAnim forKey:@strokeAnim]; //将动画添加到图层






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



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



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

  CGFloat sf = self.view.frame.size.width / 500.0; //将路径缩放的因子

然后,我们只需将我们所有的点加倍按比例因子 UIBezierPath 。例如,采用我们之前的路径:

  UIBezierPath * yourPath = [UIBezierPath bezierPath]; //创建bezier路径
[yourPath moveToPoint:CGPointMake(100.0 * sf,100.0 * sf)]; //移动到起点
[yourPath addQuadCurveToPoint:CGPointMake(300.0 * sf,500.0 * sf)controlPoint:CGPointMake(500.0 * sf,350.0 * sf)];

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



你也想要更改 CAShapeLayer 的大小,使其平方并占据整个屏幕宽度。

  yourShapeLayer.frame = CGRectMake(0,0,self.view.frame.size.width,self.view.frame.size.width); 

最后,你想要定位 CAShapeLayer 到屏幕的中心。您可以通过将图层的位置属性设置为视图的 center 来轻松完成此操作。

  yourShapeLayer.position = self.view.center; 

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





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






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


I want to draw a bezier path of the outline of Taj Mahal's tomb.

Q1. How could I draw it in XCode? I could easily do that in PS but am finding it difficult to do in XCode programmatically especially getting the coordinates of the control points.

Q2. Moreover, how can the coordinates of the points be fixed when the screen sizes vary?

Q3. How could I animate it as though an invisible pencil is drawing that on screen?

How do I draw a bezier path in UIKit?

Create a UIBezierPath object and then use the various methods on it to construct your path.

I suspect the methods you're going to be most interested in are:

For example, something like this will create a simple bezier path with a quadratic curve:

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

However, if you're used to using something like Photoshop to create your paths, you may be interested in PaintCode, that can let you create bezier paths using a 'what you see is what you get' approach.

You can add this UIBezierPath to the path property of a CAShapeLayer in order to display it on screen.

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

You can then easily set the strokeColor and lineWidth properties on the shape layer in order to customise how your path gets stroked.

yourShapeLayer.strokeColor = [UIColor redColor].CGColor; // red stroke color
yourShapeLayer.lineWidth = 5.0; // 5 point stroke width

You should end up with something like this:


How could I animate it as though an invisible pencil is drawing that on screen?

You can easily create a CABasicAnimation that can animate the strokeStart or strokeEnd property of the CAShapeLayer in order to achieve your desired animation.

This can result in the animation effect of the line 'getting drawn' onto the screen.

For example, this code will result in the strokeEnd property animating from 0.0 to 1.0, creating your desired effect:

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


How can I scale this path to work with different sized screens?

The way I usually like to solve this problem is to define the path's points in a given fixed frame (let's say 500 x 500 points), and then generate a scale factor based on the size of the screen (in your case, you want to scale to the width of the screen).

So all we have to do is generate our scale factor.

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

Then, we just have to multiple all our points in the UIBezierPath by this scale factor. For example, taking our previous path:

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)];

Now, all we have to do is program in our bezier path points as if we were always drawing it in a 500 x 500 frame (my points already fit nicely within that).

You'll also want to change the size of your CAShapeLayer so that it's squared and occupies the entire width of the screen.

yourShapeLayer.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.width);

Finally, you want to position the CAShapeLayer to the center of the screen. You can do this easily by setting the position property of the layer to the center of the view.

yourShapeLayer.position = self.view.center;

Now your path should always scale to occupy the screen's width.

(I added a gray background to the layer just to illustrate the scaling)


Full project (for your convenience): https://github.com/hamishknight/Drawing-Scaling-Animating-UIBezierPaths