# How to add rounded corner to a UIBezierPath custom rectangle?

## Question or problem with Swift language programming:

I managed to create the rounded corners, but I’m having trouble with the first rounded corner (lower right )

Question :

here is my code for the custom rectangle and a screenshot :

```let path = UIBezierPath()
path.moveToPoint(CGPoint(x: 300, y: 0))
path.addArcWithCenter(CGPoint(x: 300-10, y: 50), radius: 10 , startAngle: 0 , endAngle: CGFloat(M_PI/2)  , clockwise: true) //1st rounded corner
path.addArcWithCenter(CGPoint(x: 200, y: 50), radius:10, startAngle: CGFloat(2 * M_PI / 3), endAngle:CGFloat(M_PI) , clockwise: true)// 2rd rounded corner
path.addArcWithCenter(CGPoint(x: 200, y: 10), radius:10, startAngle: CGFloat(M_PI), endAngle:CGFloat(3 * M_PI / 2), clockwise: true)// 3rd rounded corner
// little triangle at the bottom
path.addArcWithCenter(CGPoint(x: 290, y: 10), radius: 10, startAngle: CGFloat(3 * M_PI / 2), endAngle: CGFloat(2 * M_PI ), clockwise: true)
path.closePath()
```

## How to solve the problem:

### Solution 1:

I think what you’re doing is overly complicated. UIBezierPath gives you `UIBezierPath(roundedRect:)` so why not use it? Stroke the rounded rectangle; erase the spot where you’re going to put the little triangle; add the triangle; fill the compound path; and stroke the missing two sides of the triangle. Like this (this is just some code I happened to have lying around – you should change the numbers to fit your shape, of course):

```let con = UIGraphicsGetCurrentContext()
CGContextTranslateCTM(con, 10, 10)
UIColor.blueColor().setStroke()
UIColor.blueColor().colorWithAlphaComponent(0.4).setFill()
let p = UIBezierPath(roundedRect: CGRectMake(0,0,250,180), cornerRadius: 10)
p.stroke()
CGContextClearRect(con, CGRectMake(20,170,10,11))
let pts = [
CGPointMake(20,180), CGPointMake(20,200),
CGPointMake(20,200), CGPointMake(30,180)
]
p.moveToPoint(pts[0])
p.fill()
CGContextStrokeLineSegments(con, pts, 4)
```

### Solution 2:

Instead of starting the code with a straight line :

```path.moveToPoint(CGPoint(x: 300, y: 0))
```

```path.addArcWithCenter(CGPoint(x: 300-10, y: 50), radius: 10 , startAngle: 0 , endAngle: CGFloat(M_PI/2)  , clockwise: true) //1st rounded corner
```

and by doing this, I have four rounded corners and I just need to add a straight line at the end of the code right before:

```path.closePath()
```

Here is the code and a screenshot:

```let path = UIBezierPath()
path.addArcWithCenter(CGPoint(x: 300-10, y: 50), radius: 10 , startAngle: 0 , endAngle: CGFloat(M_PI/2)  , clockwise: true) //1st rounded corner
path.addArcWithCenter(CGPoint(x: 200, y: 50), radius:10, startAngle: CGFloat(2 * M_PI / 3), endAngle:CGFloat(M_PI) , clockwise: true)// 2rd rounded corner
path.addArcWithCenter(CGPoint(x: 200, y: 10), radius:10, startAngle: CGFloat(M_PI), endAngle:CGFloat(3 * M_PI / 2), clockwise: true)// 3rd rounded corner
// little triangle
path.addArcWithCenter(CGPoint(x: 290, y: 10), radius: 10, startAngle: CGFloat(3 * M_PI / 2), endAngle: CGFloat(2 * M_PI ), clockwise: true)
path.closePath()
```

### Solution 3:

A couple of observations:

1. Make sure that you take the view `bounds` and inset it by half of the line width. That ensures that the entire stroked border falls within the `bounds` of the view. If your line width is 1, this might not be so obvious, but with larger line widths, the problem becomes more pronounced.

2. If using `draw(_:)` method, don’t use the `rect` that is passed to this method, but rather refer to the `bounds` (inset, as described above). The `CGRect` passed to `draw(_:)` is the rectangle being drawn, not necessarily the full `bounds`. (It generally is, but not always, so always refer to the `bounds` of the view, not the `rect` passed to this method.)

As the documentation says (emphasis added):

The portion of the view’s bounds that needs to be updated. The first time your view is drawn, this rectangle is typically the entire visible bounds of your view. However, during subsequent drawing operations, the rectangle may specify only part of your view.

3. I’d give all of the the various properties of the view a `didSet` observer that will trigger the view to be redrawn. That way, any IB overrides or programmatically set values will be reflected in the resulting view automatically.

4. If you want, you can make the whole thing `@IBDesignable` and make the properties `@IBInspectable`, so you can see this rendered in Interface Builder. It’s not necessary, but can be useful if you want to see this rendered in storyboards or NIBs.

5. While you can round corners using a circular arc, using a quad curve is easier, IMHO. You just specify where the arc ends and the corner of the rectangle, and the quadratic bezier will produce a nicely rounded corner. Using this technique, no calculation of angles or the center of the arc is necessary.

Thus:

```@IBDesignable
class BubbleView: UIView {
@IBInspectable var lineWidth:    CGFloat = 1       { didSet { setNeedsDisplay() } }
@IBInspectable var cornerRadius: CGFloat = 10      { didSet { setNeedsDisplay() } }
@IBInspectable var calloutSize:  CGFloat = 5       { didSet { setNeedsDisplay() } }
@IBInspectable var fillColor:    UIColor = .yellow { didSet { setNeedsDisplay() } }
@IBInspectable var strokeColor:  UIColor = .black  { didSet { setNeedsDisplay() } }

override func draw(_ rect: CGRect) {
let rect = bounds.insetBy(dx: lineWidth / 2, dy: lineWidth / 2)
let path = UIBezierPath()

// lower left corner
path.move(to: CGPoint(x: rect.minX + cornerRadius, y: rect.maxY - calloutSize))
controlPoint: CGPoint(x: rect.minX, y: rect.maxY - calloutSize))

// left

// upper left corner
controlPoint: CGPoint(x: rect.minX, y: rect.minY))

// top

// upper right corner
controlPoint: CGPoint(x: rect.maxX, y: rect.minY))

// right

// lower right corner
controlPoint: CGPoint(x: rect.maxX, y: rect.maxY - calloutSize))

// bottom (including callout)
path.addLine(to: CGPoint(x: rect.midX + calloutSize, y: rect.maxY - calloutSize))
path.addLine(to: CGPoint(x: rect.midX - calloutSize, y: rect.maxY - calloutSize))
path.close()

fillColor.setFill()
path.fill()

strokeColor.setStroke()
path.lineWidth = lineWidth
path.stroke()
}
}
```

That yields:

### Solution 4:

Swift 5 with configuration variables:

```override func draw(_ rect: CGRect) {
let arrowXOffset: CGFloat = 13
let arrowHeight: CGFloat = 6

let mainRect = CGRect(origin: rect.origin, size: CGSize(width: rect.width, height: rect.height - arrowHeight))

let leftTopPoint = mainRect.origin
let rightTopPoint = CGPoint(x: mainRect.maxX, y: mainRect.minY)
let rightBottomPoint = CGPoint(x: mainRect.maxX, y: mainRect.maxY)
let leftBottomPoint = CGPoint(x: mainRect.minX, y: mainRect.maxY)

let leftArrowPoint = CGPoint(x: leftBottomPoint.x + arrowXOffset, y: leftBottomPoint.y)
let centerArrowPoint = CGPoint(x: leftArrowPoint.x + arrowHeight, y: leftArrowPoint.y + arrowHeight)
let rightArrowPoint = CGPoint(x: leftArrowPoint.x + 2 * arrowHeight, y: leftArrowPoint.y)

let path = UIBezierPath()
startAngle: CGFloat(3 * Double.pi / 2), endAngle: CGFloat(2 * Double.pi), clockwise: true)
startAngle: 0, endAngle: CGFloat(Double.pi / 2), clockwise: true)

startAngle: CGFloat(Double.pi / 2), endAngle: CGFloat(Double.pi), clockwise: true)
startAngle: CGFloat(Double.pi), endAngle: CGFloat(3 * Double.pi / 2), clockwise: true)