background

If you want to draw rectangles, circles, ellipses, arcs, or irregular polygons, you can override UIView’s Draw (_ rect: CGRect) method and use UIBezierPath to draw.

UIBezierPath is a class in UIKit that is a wrapper around path from the Core Graphics framework.

For more information on the principles of iOS drawing, check out the blogger’s article on basic principles of iOS: UIView Drawing and Display Principles, Flow analysis and Performance Optimization

Basic properties and method description

1 UIColor.red.set()

Set the line color, which is the brush color.

2 lineWidth

Line width

3 lineCapStyle

The line cap style, which is an enumeration of CGLineCap types, is defined as follows

Public enum CGLineCap: Int32, @unchecked Sendable {/// Specifies that endpoints are not drawn, that is, the line ends directly. Case butt = 0 /// Draw round ends, i.e., draw a semicircle at the end of the line whose diameter is the width of the line. Case round = 1 /// Draw square ends, i.e., draw half a square at the end of the line whose side length is the width of the line. Case square = 2} case square = 2} case square = 2}Copy the code

The result is a one-to-one correspondence between the order and the enumeration order

4 lineJoinStyle

The line join style, or corner style, is an enumeration of CGLineJoin types, as defined below

public enum CGLineJoin : + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Copy the code

The result is a one-to-one correspondence between the order and the enumeration order

5 stroke()

Stroke gets an unfilled view, that is, only a curved path is drawn.

6 fill()

Fill gets a view that is filled inside, that is, the geometry formed by the curve is filled with brush colors.

Draw a rectangle

Draw by init(rect: CGRect) method as follows

override func draw(_ rect: CGRect) { UIColor.red.set() let path1 = UIBezierPath(rect: CGRect(x: 100, y: 100, width: 200, height: LineCapStyle =.round path1.linejoinstyle =.round path1.linejoinstyle =.round path1.stroke() let path2 = UIBezierPath(rect: CGRect(x: 100, y: 230, width: 200, height: 200)) path2.lineWidth = 5.0 path2.linecapstyle =.round path2.linejoinstyle =.round path2.fill()}Copy the code

Draw a rectangle with rounded corners

There are two ways. If all four corners need rounded corners, you can draw them using the init(roundedRect rect: CGRect, cornerRadius: CGFloat) method.

If only certain rounded corners are required, you can use the init(roundedRect rect: CGRect, byRoundingCorners: UIRectCorner, cornerRadii: CGSize) method to draw.

The following code

override func draw(_ rect: CGRect) { UIColor.red.set() let path1 = UIBezierPath(roundedRect: CGRect(x: 100, y: 100, width: 200, height: 100), cornerRadius: LineCapStyle =.round path1.linejoinstyle =.round path1.linejoinstyle =.round path1.stroke() let path2 = UIBezierPath(roundedRect: CGRect(x: 100, y: 230, width: 200, height: 200), byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width: 10, height: 5)) path2.lineWidth = 5.0 path2.linecapstyle =.round path2.linejoinstyle =.round path2.fill()}Copy the code

Draw polygons

Draw by move(to Point: CGPoint) and addLine(to Point: CGPoint). MoveToPoint: This method sets the starting point, which means to start at this point. AddLineToPoint: Sets the point through which the polygon you want to create passes, i.e. the point where the two lines intersect. Successive lines can be created. Each line starts at the previous end point, and the end point is the specified point. Finally, the fifth line is obtained using path.close(). The closePath method not only ends the subpath statement of a shape, it also draws a line segment between the last point and the first point. This is a convenient method, so we don’t need to draw the last line. The following code

override func draw(_ rect: CGRect) {
    UIColor.red.set()
    let path = UIBezierPath()
    path.lineWidth = 5.0
    path.lineCapStyle = .round
    path.lineJoinStyle = .round
    path.move(to: CGPoint(x: 100, y: 300))
    path.addLine(to: CGPoint(x: 200, y: 200))
    path.addLine(to: CGPoint(x: 300, y: 300))
    path.addLine(to: CGPoint(x: 260, y: 400))
    path.addLine(to: CGPoint(x: 140, y: 400))
    path.close()
    path.fill()
}
Copy the code

Draw the ellipse

Draw by init(ovalIn Rect: CGRect) to get the inscribed ellipse of the rectangle if the rect passed in is a rectangle, and the inscribed circle of the square if the rect passed in is a square. The following code

override func draw(_ rect: CGRect) { UIColor.red.set() let path1 = UIBezierPath(ovalIn: CGRect(x: 100, y: 100, width: 200, height: LineCapStyle =.round path1.linejoinstyle =.round path1.linejoinstyle =.round path1.stroke() let path2 = UIBezierPath(ovalIn: CGRect(x: 100, y: 230, width: 200, height: 200)) path2.lineWidth = 5.0 path2.linecapstyle =.round path2.linejoinstyle =.round path2.fill()}Copy the code

Draw an arc

By init(arcCenter Center: CGPoint, RADIUS: CGFloat, startAngle: CGFloat, endAngle: CGFloat, clockwise: Bool) method drawing, where arcCenter refers to the coordinates of the center of the circle, RADIUS refers to the radius of the circle, startAngle refers to the beginning Angle of the circle, endAngle refers to the ending Angle of the circle, which is clockwise. The angular reference frame of the arc is as follows

The following code

override func draw(_ rect: CGRect) { UIColor.red.set() let path1 = UIBezierPath(arcCenter: CGPoint(x: 200, y: 250), radius: 100, startAngle: 180 / 180 * .pi, endAngle: 45 / 180 * .pi, clockwise: True) path1.lineWidth = 5.0 path1.linecapstyle =.round path1.linejoinstyle =.round path1.stroke() let path2 = UIBezierPath(arcCenter: CGPoint(x: 200, y: 450), radius: 100, startAngle: 0, endAngle: 2 * .pi, clockwise: LineCapStyle =.round Path2.linejoinstyle =.round path2.fill()}Copy the code

Draw a quadratic Bezier curve

Draw by addQuadCurve(to endPoint: CGPoint, controlPoint: CGPoint) method. The curve segment starts at the current point and ends at the specified point. The tangential definition of a controlPoint is shown as follows

The following code

override func draw(_ rect: CGRect) {uicolor.red.set () let path1 = UIBezierPath() path1.lineWidth = 5.0 path1.linecapstyle =.round path1.lineJoinStyle = .round path1.move(to: CGPoint(x: 100, y: 200)) path1.addQuadCurve(to: CGPoint(x: 300, y: 200), controlPoint: CGPoint(x: 100, y: 100)) path1.stroke() let path2 = UIBezierPath() path2.lineWidth = 5.0 path2.linecapstyle =.round path2.linejoinstyle = .round path2.move(to: CGPoint(x: 100, y: 250)) path2.addQuadCurve(to: CGPoint(x: 300, y: 250), controlPoint: CGPoint(x: 250, y: 400)) path2.fill() }Copy the code

Draw bezier curves three times

Draw by addCurve(to endPoint: CGPoint, controlPoint1: CGPoint, controlPoint2: CGPoint). The curve segment starts at the current point and ends at the specified point. The tangents of the two control points are defined as shown below

The following code

override func draw(_ rect: CGRect) {uicolor.red.set () let path1 = UIBezierPath() path1.lineWidth = 5.0 path1.linecapstyle =.round path1.lineJoinStyle = .round path1.move(to: CGPoint(x: 100, y: 200)) path1.addCurve(to: CGPoint(x: 300, y: 200), controlPoint1: CGPoint(x: 150, y: 50), controlPoint2: CGPoint(x: 250, y: 350)) path1.stroke() let path2 = UIBezierPath() path2.lineWidth = 5.0 path2.linecapstyle =.round path2.linejoinstyle = .round path2.move(to: CGPoint(x: 100, y: 350)) path2.addCurve(to: CGPoint(x: 300, y: 350), controlPoint1: CGPoint(x: 150, y: 200), controlPoint2: CGPoint(x: 250, y: 500)) path2.fill() }Copy the code

Draw a dotted line

SetLineDash (_ pattern: UnsafePointer? , count: Int, phase: CGFloat).

Where Pattern is a C-style array of floating-point values containing line segments and the length (in points) of gaps in the pattern. The values in the array alternate, starting with the first segment length, followed by the first gap length, followed by the second segment length, and so on.

Count is the number of values in the schema, the number of dashed array elements.

Phase is where the dotted line begins, the offset at which the pattern is drawn, measured along the point of the dotted line pattern. For example, a phase value of phase 6 for pattern 5-2-3-2 would cause the drawing to begin in the middle of the first gap.

The following code

override func draw(_ rect: CGRect) {uicolor.red.set () let path1 = UIBezierPath() path1.lineWidth = 5.0 path1.linecapstyle =.round path1.lineJoinStyle = .round path1.move(to: CGPoint(x: 50, y: 200)) path1.addLine(to: CGPoint(x: 400, y: 200)) var dashConfig1:[CGFloat] = [10.0, 15.0] path1.setLineDash(&dashConfig1, count: dashConfig1.count, phase: 0) path1.stroke() let path2 = UIBezierPath() path2.lineWidth = 5.0 path2.linecapstyle =.round path2.linejoinstyle = .round path2.move(to: CGPoint(x: 50, y: 250)) path2.addLine(to: CGPoint(x: 400, y: 250)) var dashConfig2:[CGFloat] = [10.0, 15.0, 15.0, 25.0] path2.setLinedAsh (&dashConfig2, count: dashConfig2.count, phase: 0) path2.stroke() }Copy the code