Last active
October 7, 2015 17:01
-
-
Save jordanekay/3556830428f56e4850ea to your computer and use it in GitHub Desktop.
Replacement implementation of round-rect UIBezierPaths
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Darwin | |
private typealias Point = (x: CGFloat, y: CGFloat) | |
private typealias Points = (Point, Point?) | |
extension UIBezierPath { | |
public convenience init(rect: CGRect, cornerRadius radius: CGFloat, roundedCorners: UIRectCorner = .AllCorners) { | |
self.init() | |
let path = Path(rect: rect, radius: radius, roundedCorners: roundedCorners) | |
drawPath(path) | |
} | |
} | |
private enum Corner: Int { | |
case BottomRight | |
case BottomLeft | |
case TopLeft | |
case TopRight | |
var startAngle: CGFloat { | |
return CGFloat(Double(rawValue) * M_PI_2) | |
} | |
var endAngle: CGFloat { | |
return startAngle + CGFloat(M_PI_2) | |
} | |
var rectCorner: UIRectCorner { | |
switch self { | |
case .TopLeft: return .TopLeft | |
case .TopRight: return .TopRight | |
case .BottomRight: return .BottomRight | |
case .BottomLeft: return .BottomLeft | |
} | |
} | |
} | |
private struct Path { | |
let rect: CGRect | |
let radius: CGFloat | |
let roundedCorners: UIRectCorner | |
func pointsForCorner(corner: Corner) -> (CGPoint, CGPoint?) { | |
let points: Points | |
let minX = CGRectGetMinX(rect) | |
let minY = CGRectGetMinY(rect) | |
let maxX = CGRectGetMaxX(rect) | |
let maxY = CGRectGetMaxY(rect) | |
let rounded = roundedCorners.contains(corner.rectCorner) | |
switch corner { | |
case .TopLeft: | |
points = rounded ? ((minX, minY + radius), (minX + radius, minY + radius)) : ((minX, minY), nil) as Points | |
case .TopRight: | |
points = rounded ? ((maxX - radius, minY), (maxX - radius, minY + radius)) : ((maxX, minY), nil) as Points | |
case .BottomRight: | |
points = rounded ? ((maxX, maxY - radius), (maxX - radius, maxY - radius)) : ((maxX, maxY), nil) as Points | |
case .BottomLeft: | |
points = rounded ? ((minX + radius, maxY), (minX + radius, maxY - radius)) : ((minX, maxY), nil) as Points | |
} | |
let mapping = { CGPoint(x: ($0 as Point).x, y: $0.y) } | |
return (mapping(points.0), points.1.map(mapping)) | |
} | |
} | |
private extension UIBezierPath { | |
func drawPath(path: Path) { | |
let (start, _) = path.pointsForCorner(.TopLeft) | |
moveToPoint(start) | |
for corner: Corner in [.TopLeft, .TopRight, .BottomRight, .BottomLeft] { | |
let points = path.pointsForCorner(corner) | |
addLineToPoint(points.0) | |
if let center = points.1 { | |
addArcWithCenter(center, radius: path.radius, startAngle: corner.startAngle, endAngle: corner.endAngle, clockwise: true) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment