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:
moveToPoint:
(Fairly self-explanitary, moves the current point to a given point)addLineToPoint:
(Adds a straight line, starting at the current point and ending at a given point)addCurveToPoint:controlPoint1:controlPoint2:
(Adds a bezier curve, starting the current point, with a set end point and control points)addQuadCurveToPoint:controlPoint:
Adds a quadratic curve, starting at the current point, with a set end point and control point.For example, something like this will create a simple bezier path with a quadratic curve:
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 thepath
property of aCAShapeLayer
in order to display it on screen.You can then easily set the
strokeColor
andlineWidth
properties on the shape layer in order to customise how your path gets stroked.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 thestrokeStart
orstrokeEnd
property of theCAShapeLayer
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 from0.0
to1.0
, creating your desired effect: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.
Then, we just have to multiple all our points in the
UIBezierPath
by this scale factor. For example, taking our previous path: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.Finally, you want to position the
CAShapeLayer
to the center of the screen. You can do this easily by setting theposition
property of the layer to thecenter
of the view.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
I blogged about this in 2010: Animating the Drawing of a CGPath With CAShapeLayer.
The gist of it is this:
UIBezierPath
orCGPath
with the shape you want to draw. Use the methodsmoveToPoint:
,addLineToPoint:
,addCurveToPoint:controlPoint1:controlPoint2:
etc. to create the shape.CGShapeLayer
and assign the path to the layer'spath
property.[self.view.layer addSublayer:shapeLayer];
). You also have to give the layer a valid size and position (frame
).strokeEnd
property from 0 to 1.The answer posted by originaluser2 solves everything. You can also try this way, if you want to resize the bezier path for different dievice screens:
You can simply subclass the UIView and customise its drawRect method:
frame 50x50:
frame 100x100:
frame 100x50
This draws a bezier curve in a frame of size 50x50 if you send frame of size 50x50. Also this code get resized automatically based on the frame size it recieves.