The previous article mentioned the use of Bezier curve to achieve the drawing board (portal), immediately on the Bezier curve interest greatly increased with wood.
The reason for touching the Bezier curve is thanks to master. Friday before work, Master left me a task, let me go home on the weekend to study the IPhone download App when the effect is implemented (do not know the effect of children's shoes See)
As shown, the process effect of downloading the app is that the app icon has a clockwise-rotated circle in the middle. The APP downloads when you're done with a lap.
Just gave me the task of the time, suddenly feel good difficult to have wood ... (mainly because I didn't know the Bezier curve at that time.)
Aside from all the complexities, let's just talk today about how to make a circle go through a circle like this. is to use the Bezier curve to draw a fan. But before we introduce how to draw a fan, let's start with the basics and get to know Uibezierpath.
PS: Although the content of this article is a bit long, but it is not difficult, do not be afraid, after reading can use Uibezierpath do some basic operation. At the end of the article we'll talk about the plays: animating the app when it's downloaded. )
We are divided into straight line segment and curve segment two kind of speaking.
Let 's review the above (it doesn't matter if you don't see it). in the previous article, we talked about how to implement drawing board, in essence, it is implemented by straight line segment: Record the initial and sliding coordinates of the touch, and connect a straight line between the two. The main methods are movetopoint: and Addlinetopoint:
Some children's shoes may ask, why can you draw a curve?
Actually, it's not. You draw a curve that may take 0.1 seconds (assuming), but actually I draw a straight line every 0.0000000001 seconds (assuming), so that a large number of small straight line segments are connected, and finally the macro looks like a curve, but in essence, from a microscopic point of view, it is a very large number of small straight segments.
The above paragraph is not important, can not understand and nothing, we continue to say the focus of this article.
Know how to draw a straight line, then the square, rectangle, polygon is good to do.
Let's start with a poly (e.g. Pentagon) chestnut . Use the existing knowledge to think about, how to achieve?
It's simple, as long as there are five vertex coordinates, you can connect them with straight segments:
Override func drawRect(rect: CGRect) { // pentagon
Let color = UIColor.redColor()
Color.set() // set the line color
Let aPath = UIBezierPath()
aPath.lineWidth = 5.0 // line width
aPath.lineCapStyle = .Round // line corner
aPath.lineJoinStyle = .Round // End point processing
// Set the starting point of the shape.
aPath.moveToPoint(CGPointMake(100, 10))
// Draw the lines
aPath.addLineToPoint(CGPointMake(200, 40))
aPath.addLineToPoint(CGPointMake(160, 140))
aPath.addLineToPoint(CGPointMake(40, 140))
aPath.addLineToPoint(CGPointMake(10, 40))
aPath.closePath() // The last line is obtained by calling the closePath method.
aPath.stroke() // Draws line is wired according to the coordinate point, not filled
// aPath.fill() // Draws line is lined according to coordinate points, padding
}
Some children's shoes may have noticed: "Why did you just draw four lines?" What's Closepath doing? ”
One simple way to draw the last line is to call the Closepath method, which automatically connects the line between the end point and the beginning to form a closed graph.
We've already used the stroke (), which is the connection. So what's the last sentence fill ()? The stroke () is only wired and will not be populated. If you want to fill the effect, use fill () to achieve:
As shown in. The image on the left is the effect of the stroke () and the effect of fill () on the right.
(PS: Do not call DrawRect directly when redrawing is required: method, call Setneedsdisplay system will automatically call DrawRect: method)
is not very simple. Think of the rectangle, square how to draw? With the method of drawing Pentagon and so on, the coordinates of the four vertices can be connected.
Well, that's OK. But there is an easier way to use the init(rect:cgrect) method of the Uibezierpath class.
If the incoming width is equal, the drawing is a square, otherwise it is a rectangle (nonsense)
// rectangle
Override func drawRect(rect: CGRect) {
Let color = UIColor.redColor()
Color.set() // set the line color
Let aPath = UIBezierPath(rect: CGRectMake(40, 40, 100, 50)) // rectangle
// let aPath = UIBezierPath(rect: CGRectMake(40, 40, 100, 100)) // Square
aPath.lineWidth = 5.0 // line width
aPath.lineCapStyle = .Round // line corner
aPath.lineJoinStyle = .Round // End point processing
aPath.stroke() // Draws line is wired according to the coordinate point, not filled
// aPath.fill() // Draws line is lined according to coordinate points, padding
}
The effect is as shown in two different ways, the left is the stroke () and the right is fill (). Squares are the same.
OK, the straight line is about the same, let's talk about the curve section below.
how to draw a circle/ellipse? You can use the Uibezierpath init(ovalinrect rect:cgrect) method.
What does that mean? When we pass in a rectangular frame, we draw the rectangle's inscribed circle.
If the rectangle is a square, then the inscribed circle is drawn. If the rectangle is a rectangle, then the inner-tangent ellipse is drawn.
// circle, ellipse
Override func drawRect(rect: CGRect) {
Let color = UIColor.redColor()
Color.set() // set the line color
// Draw an inscribed circle/ellipse based on the rectangle of the descendant
// let aPath = UIBezierPath(ovalInRect: CGRectMake(40, 40, 100, 100)) // If the square is passed in, draw the inscribed circle
Let aPath = UIBezierPath(ovalInRect: CGRectMake(40, 40, 100, 160)) // If the rectangle is passed in, the inscribed ellipse is drawn
aPath.lineWidth = 5.0 // line width
aPath.stroke() // Draws line is wired according to the coordinate point, not filled
// aPath.fill() // Draws line is lined according to coordinate points, padding
}
In the case of an ellipse, the same stroke () and fill () are shown in the same way as the circle:
Note that the incoming rectangle frame is just to draw its inscribed circle, and the rectangle is not drawn.
Well, it's getting to the point. Before you draw a fan, let's say how to draw an arc. These two are different.
, this is a One-fourth-circle arc. How does it come true? Using the Uibezierpath class of init(arccenter Center:cgpoint, Radius:cgfloat , StartAngle: CGFloat , Endangle: CGFloat , clockwise: Bool ) method.
Many parameters, respectively: Center is the center coordinate, radius is the radius length, startangle is the starting point, Endangle is the end, clockwise is true clockwise, false is counterclockwise.
Let's take a look at the official documentation:
Have you noticed? 0 is the point on the right, not the one above.
The code is as an example of an arc with a four-point circle:
// arc
Override func drawRect(rect: CGRect) {
Let color = UIColor.redColor()
Color.set() // set the line color
Let aPath = UIBezierPath(arcCenter: CGPointMake(150, 150), radius: 75,
startAngle: 0, endAngle: (CGFloat)(90*M_PI/180), clockwise: true)
aPath.lineWidth = 5.0 // line width
aPath.stroke() // Draws line is wired according to the coordinate point, not filled
// aPath.fill() // Draws line is lined according to coordinate points, padding
}
So how does a fan make it? Say a One-fourth circle. Some children's shoes may say: Fill () not on the line.
Not. Let's take a look at the effect of changing the above code to fill ():
is not very unexpected. It is filled, but not filled to the center, and the effect is different from what we want.
How do you draw that fan?
In fact, it's just a fill (), but we need to connect a line between the end point and the center of the circle, and then a line between the center and the starting point, then fill with fill ().
The code below, the last line (center to start) We also use Closepath to achieve:
// sector
Override func drawRect(rect: CGRect) {
Let color = UIColor.redColor()
Color.set() // set the line color
Let aPath = UIBezierPath(arcCenter: CGPointMake(150, 150), radius: 75,
startAngle: 0, endAngle: (CGFloat)(90*M_PI/180), clockwise: true)
aPath.addLineToPoint(CGPointMake(150, 150))
aPath.closePath()
aPath.lineWidth = 5.0 // line width
// aPath.stroke() // Draws line is wired according to the coordinate point, not filled
aPath.fill() // Draws line is filled according to the coordinate point, filled
}
The effect is as follows:
perfect! Now think about the article at the beginning of the download App when the effect, is not the idea.
We set the startangle to the point above, and then we downloaded how much, we drew the fan and changed the Endangle to the downloaded part.
For example, if the download is 10%, then we will draw a One-tenth fan. Half of the download, then we'll draw a semicircle.
Of course, this is just a simple, concrete implementation of the other details. But with the idea, I believe it can be achieved.
Let's give a simple chestnut . Let's say that an app took a total of two seconds to download and download One-twentieth every 0.1 seconds (which is just a hypothesis).
So we can draw a one-twentieth sector every 0.1 seconds, and after two seconds the whole circle is finished. On the code:
/ / Realize the effect of App download
Var beginAngle = M_PI*3/2 // starting point
Var finishAngle = M_PI*3/2+M_PI*2/20 // End point
Override func drawRect(rect: CGRect) {
Let color = UIColor.whiteColor()
Color.set() // set the line color
Let aPath = UIBezierPath(arcCenter: CGPointMake(150, 150), radius: 75, startAngle: (CGFloat)(beginAngle), endAngle: (CGFloat)(finishAngle), clockwise: true)
aPath.addLineToPoint(CGPointMake(150, 150))
aPath.closePath()
aPath.lineWidth = 5.0 // line width
aPath.fill() // Draws line is filled according to the coordinate point, filled
finishAngle += M_PI/20 // update the end point
}
This code is almost the same as before, the only difference is that each time we finish, we will update the end point, let it more than One-twentieth circle.
Then it executes every 0.1 seconds, and after 2 seconds, it stops executing. On the code:
Class ViewController: UIViewController {
Let myView = MyView.init(frame: CGRectZero) // Our custom view
Var timer: NSTimer! // timer
Override func viewDidLoad() {
super.viewDidLoad()
myView.frame = view.bounds
view.addSubview(myView)
// execute every 0.1 seconds
Timer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self,
Selector: Selector("reDrawView"), userInfo: nil, repeats: true)
}
Func reDrawView() {
myView.setNeedsDisplay() // redraw the interface
// Stop after finishing a circle
If myView.finishAngle > myView.beginAngle+M_PI*2 {
Timer.invalidate() // stop timer
}
}
}
The final effect is shown in the GIF image below:
Some children's shoes may say, but you this is not translucent, the app download when the circle is translucent ah!
all you need to do is change the fill () to Fillwithblendmode (. Normal , Alpha: 0.5 The line will be translucent as it is drawn.
Good job! When it's really done, we'll modify the end point based on the progress of the download. Of course, these are just my personal thoughts, if there is a better way to welcome the discussion.
Complete demo Please see my github:https://github.com/963239327/uibezierpathdemo don't forget the star in the upper right corner!
swift-Bezier curve Fan, arc, Circle, Polygon--uibezierpath to achieve the animation effect when the app is downloaded