Skip to content

Instantly share code, notes, and snippets.

@renssies
Last active October 25, 2023 14:14
Show Gist options
  • Save renssies/96ab3ba1426ad97fa91497b59a4d73c3 to your computer and use it in GitHub Desktop.
Save renssies/96ab3ba1426ad97fa91497b59a4d73c3 to your computer and use it in GitHub Desktop.
Rounded UIBezierPath without clamping bug
extension UIBezierPath {
/// Creates a rounded rectangle without clamping the corner radius the 1/3 of the rects width or height.
/// This can be used to workout a bug in the standard `UIBezierPath(roundedRect:cornerRadius)`.
///
/// It will however clamp the corner radius to a max of half the width or height of the rect, this is to avoid incorrect drawing.
/// - Parameters:
/// - rect: The rectangle that defines the basic shape of the path
/// - cornerRadius: The radius of each corner oval. A value of 0 results in a rectangle without rounded corners. Values larger than half the rectangle’s width or height are clamped appropriately to half the width or height.
convenience init(unclampedRoundedRect rect: CGRect, cornerRadius: CGFloat) {
self.init()
let cornerRadius = min(cornerRadius, rect.width / 2, rect.height / 2)
let path = self
path.move(to: CGPoint(x: 0 + cornerRadius, y: 0)); // Move to top left but inset with radius
path.addLine(to: CGPoint(x: rect.width - cornerRadius, y: 0)) // Add line at the top from left to right
path.addArc(withCenter: CGPoint(x: rect.width - cornerRadius, y: cornerRadius), radius: cornerRadius, startAngle: 3 * .pi / 2, endAngle: 0, clockwise: true) // Add top right rounded corner
path.addLine(to: CGPoint(x: rect.width, y: rect.height - cornerRadius)) // Add line from top to bottom on right side
path.addArc(withCenter: CGPoint(x: rect.width - cornerRadius, y: rect.height - cornerRadius), radius: cornerRadius, startAngle: 0, endAngle: .pi / 2, clockwise: true) // Add bottom right rounded corner
path.addLine(to: CGPoint(x: cornerRadius, y: rect.height)) // Add line from bottom right to bottom left
path.addArc(withCenter: CGPoint(x: cornerRadius, y: rect.height - cornerRadius), radius: cornerRadius, startAngle: .pi / 2, endAngle: .pi, clockwise: true) // Add bottom left rounded corner
path.addLine(to: CGPoint(x: 0, y: cornerRadius)) // Add line from bottom to top on left side
path.addArc(withCenter: CGPoint(x: cornerRadius, y: cornerRadius), radius: cornerRadius, startAngle: .pi, endAngle: 3 * .pi / 2, clockwise: true) // Add top left rounded corner
path.close() // Complete the path
}
}
@callo90
Copy link

callo90 commented Oct 20, 2022

You're not considering the X and Y origins, I made some changes.

`let cornerRadius = min(cornerRadius, rect.width / 2, rect.height / 2)
let originX = rect.origin.x
let originY = rect.origin.y
let width = rect.size.width
let height = rect.size.height

    let path = self
    path.move(to: CGPoint(x: originX + cornerRadius, y: originY)) // Move to top left but inset with radius
    path.addLine(to: CGPoint(x: originX + width - cornerRadius, y: originY)) // Add line at the top from left to right
    path.addArc(withCenter: CGPoint(x: originX + width - cornerRadius, y: originY + cornerRadius),
                radius: cornerRadius, startAngle: 3 * .pi / 2, endAngle: 0,
                clockwise: true) // Add top right rounded corner
    
    path.addLine(to: CGPoint(x: originX + width, y: originY + height - cornerRadius)) // Add line from top to bottom on right side
    path.addArc(withCenter: CGPoint(x: originX + width - cornerRadius, y: originY + height - cornerRadius),
                radius: cornerRadius, startAngle: 0, endAngle: .pi / 2,
                clockwise: true) // Add bottom right rounded corner
    
    path.addLine(to: CGPoint(x: originX + cornerRadius, y: originY + height)) // Add line from bottom right to bottom left
    path.addArc(withCenter: CGPoint(x: originX + cornerRadius, y: originY + height - cornerRadius),
                radius: cornerRadius, startAngle: .pi / 2, endAngle: .pi,
                clockwise: true) // Add bottom left rounded corner
    
    path.addLine(to: CGPoint(x: originX, y: originY + cornerRadius)) // Add line from bottom to top on left side
    path.addArc(withCenter: CGPoint(x: originX + cornerRadius, y: originY + cornerRadius),
                radius: cornerRadius, startAngle: .pi, endAngle: 3 * .pi / 2,
                clockwise: true) // Add top left rounded corner
    path.close() // Complete the path`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment