Skip to content

Instantly share code, notes, and snippets.

@coffeeexistence
Created March 16, 2021 01:36
Show Gist options
  • Save coffeeexistence/0d7fc5dde5eca92b6c9dcc13848fdaab to your computer and use it in GitHub Desktop.
Save coffeeexistence/0d7fc5dde5eca92b6c9dcc13848fdaab to your computer and use it in GitHub Desktop.
Animatable capsule/rounded rect path
func makeCapsuleBorderPath(_ size: CGSize) -> CGPath {
// Have to create the path manually because "UIBezierPath(roundedRect:" creates a path
// that appears visually correct, but is actually uneven. This is only apparent when
// animating strokeStart or strokeEnd on a CAShapeLayer.
let path = UIBezierPath()
let centerY = size.height / 2
let centerX = size.width / 2
let cornerRadius = size.height / 2
let topY: CGFloat = 0
let bottomY = size.height
let leftCornerX = cornerRadius
let rightCornerX = size.width - cornerRadius
let leftArcCenterPoint = CGPoint(x: leftCornerX, y: centerY)
let rightArcCenterPoint = CGPoint(x: rightCornerX, y: centerY)
let centerTopPoint = CGPoint(x: centerX, y: topY)
path.move(to: centerTopPoint)
path.addLine(to: CGPoint(x: rightCornerX, y: topY))
path.addArc(
withCenter: rightArcCenterPoint,
radius: centerY,
startAngle: deg2rad(-90),
endAngle: deg2rad(90),
clockwise: true
)
path.addLine(to: CGPoint(x: leftCornerX, y: bottomY))
path.addArc(
withCenter: leftArcCenterPoint,
radius: centerY,
startAngle: deg2rad(90),
endAngle: deg2rad(-90),
clockwise: true
)
path.addLine(to: centerTopPoint)
path.close()
return path.cgPath
}
@Sergionius
Copy link

Hello, thanks for info about "UIBezierPath(roundedRect:", but your path don't use cornerRadius as it should be, if you create for example a rectangle with width: 120, height: 40 and set cornerRadius = 8, you didn't have this cornerRadius, your code create rectangle with cornerRadius = 20, here is how create rectangle with correct cornerRadius

let cornerRadius: CGFloat = 8
let path = UIBezierPath()
path.move(to: CGPoint(x: rect.midX, y: rect.minY))
path.addLine(to: CGPoint(x: rect.maxX - cornerRadius, y: rect.minY))
path.addArc(withCenter: CGPoint(x: rect.maxX - cornerRadius, y: rect.minY + cornerRadius),
radius: cornerRadius,
startAngle: CGFloat(-Double.pi / 2),
endAngle: 0,
clockwise: true)
path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY - cornerRadius))
path.addArc(withCenter: CGPoint(x: rect.maxX - cornerRadius, y: rect.maxY - cornerRadius),
radius: cornerRadius,
startAngle: 0,
endAngle: CGFloat(Double.pi / 2),
clockwise: true)
path.addLine(to: CGPoint(x: rect.minX + cornerRadius, y: rect.maxY))
path.addArc(withCenter: CGPoint(x: rect.minX + cornerRadius, y: rect.maxY - cornerRadius),
radius: cornerRadius,
startAngle: CGFloat(Double.pi / 2),
endAngle: CGFloat(Double.pi),
clockwise: true)
path.addLine(to: CGPoint(x: rect.minX, y: rect.minY + cornerRadius))
path.addArc(withCenter: CGPoint(x: rect.minX + cornerRadius, y: rect.minY + cornerRadius),
radius: cornerRadius,
startAngle: CGFloat(Double.pi),
endAngle: CGFloat(-Double.pi / 2),
clockwise: true)
path.close()

@coffeeexistence
Copy link
Author

@Sergionius thank you very much! I'll look through and update if I ever get back around to this :)

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