Draw CALayer border around UIView - ios

I want to draw a border with open gaps around a rounded UIView.
What I currently have is this result:
What I want to achieve is that the gray borders are laying outside the yellow view. Now they are drawn that the middle of the gray line is still in the yellow.
I tried with a mask but then only the oudside ofcourse is cut.
My code:
struct Config {
let start: CGFloat
let end: CGFloat
let color: UIColor
}
extension UIView {
func drawBorders(for configs: [Config], lineWidth: CGFloat = 3.5) {
let circlePath = UIBezierPath(arcCenter: CGPoint (x: self.bounds.size.width / 2,
y: self.bounds.size.height / 2),
radius: self.bounds.size.width / 2,
startAngle: CGFloat(-0.5 * Double.pi),
endAngle: CGFloat(1.5 * Double.pi),
clockwise: true)
for config in configs {
let circleShape = CAShapeLayer()
circleShape.path = circlePath.cgPath
circleShape.strokeColor = config.color.cgColor
circleShape.fillColor = UIColor.clear.cgColor
circleShape.lineWidth = lineWidth
circleShape.strokeStart = config.start
circleShape.strokeEnd = config.end
self.layer.addSublayer(circleShape)
// let maskLayer = CAShapeLayer()
// maskLayer.frame = self.bounds
// maskLayer.path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: self.bounds.size.width / 2, height: self.bounds.size.width / 2)).cgPath
// self.layer.mask = maskLayer
}
}
}
Also added the mask code in comment to show what I have tried.
Test code:
let roundView = UIView(frame: CGRect(x: 100, y: 100, width: 150, height: 150))
roundView.backgroundColor = .yellow
roundView.layer.cornerRadius = roundView.frame.size.width / 2
let config1 = Config(start: 0.125, end: 0.25, color: .gray)
let config2 = Config(start: 0.375, end: 0.5, color: .gray)
let config3 = Config(start: 0.625, end: 0.75, color: .gray)
let config4 = Config(start: 0.875, end: 1, color: .gray)
roundView.drawBorders(for: [config1, config2, config3, config4])
view.addSubview(roundView)
Can someone please help me out?

Change your circlePath .... include linewidth in radius will resolve your issue
let circlePath = UIBezierPath(arcCenter: CGPoint (x: self.bounds.size.width / 2,
y: self.bounds.size.height / 2),
radius: (self.bounds.size.width / 2) + lineWidth/2,
startAngle: CGFloat(-0.5 * Double.pi),
endAngle: CGFloat(1.5 * Double.pi),
clockwise: true)

Related

Add Shadow to CAShapeLayer with UIBezierPath

need some help adding a drop shadow to a line created with a CAShapeLayer / UIBezierPath
This code snippet produces the following line shape as in the screenshot below
let bounds = UIScreen.main.bounds
let shapeLayer = CAShapeLayer()
shapeLayer.lineWidth = 10.0
shapeLayer.frame = CGRect(x: 0, y: 0 , width: bounds.width, height: bounds.width)
shapeLayer.lineWidth = 5.0
shapeLayer.strokeColor = UIColor.red.cgColor
let offset : CGFloat = 20
let arcCenter = shapeLayer.position
let radius = shapeLayer.bounds.size.width / 2.0 - offset
let startAngle = CGFloat(0.0)
let endAngle = CGFloat(1.0 * .pi)
let circlePath = UIBezierPath(arcCenter: arcCenter, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: true)
shapeLayer.shadowOffset = CGSize(width: 0, height: 0)
shapeLayer.shadowColor = UIColor.red.cgColor
shapeLayer.shadowOpacity = 1.0
shapeLayer.shadowRadius = 25
shapeLayer.path = circlePath.cgPath
As you can see the shadow surrounds the outer part of the semi-circle shape.
Could anyone give me any hints on adding a drop shadow around the line only ?
Output:
UIView Extension:
extension UIView {
func renderCircle() {
let semiCircleLayer = CAShapeLayer()
let center = CGPoint (x: self.frame.size.width / 2, y: self.frame.size.height / 2)
let circleRadius = self.frame.size.width / 2
let circlePath = UIBezierPath(arcCenter: center, radius: circleRadius, startAngle: CGFloat(Double.pi * 2), endAngle: CGFloat(Double.pi), clockwise: true)
semiCircleLayer.path = circlePath.cgPath
semiCircleLayer.strokeColor = UIColor.red.cgColor
semiCircleLayer.fillColor = UIColor.clear.cgColor
semiCircleLayer.lineWidth = 8
semiCircleLayer.shadowColor = UIColor.red.cgColor
semiCircleLayer.shadowRadius = 25.0
semiCircleLayer.shadowOpacity = 1.0
semiCircleLayer.shadowPath = circlePath.cgPath.copy(strokingWithWidth: 25, lineCap: .round, lineJoin: .miter, miterLimit: 0)
semiCircleLayer.shadowOffset = CGSize(width: 1.0, height: 1.0)
self.layer.addSublayer(semiCircleLayer)
}
}
Usage:
semiCircleView.renderCircle()

Creating a thin black circle (unfilled) within a filled white circle (UIButton)

I'm trying to replicate the default camera button on iOS devices:
I'm able to create a white circular button with black button within it. However, the black button is also filled, instead of just being a thin circle.
This is what I have (most of it has been copied from different sources and put together, so the code isn't efficient)
The object represents the button,
func applyRoundCorner(_ object: AnyObject) {
//object.layer.shadowColor = UIColor.black.cgColor
//object.layer.shadowOffset = CGSize(width: 0.0, height: 2.0)
object.layer.cornerRadius = (object.frame.size.width)/2
object.layer.borderColor = UIColor.black.cgColor
object.layer.borderWidth = 5
object.layer.masksToBounds = true
//object.layer.shadowRadius = 1.0
//object.layer.shadowOpacity = 0.5
var CircleLayer = CAShapeLayer()
let center = CGPoint (x: object.frame.size.width / 2, y: object.frame.size.height / 2)
let circleRadius = object.frame.size.width / 6
let circlePath = UIBezierPath(arcCenter: center, radius: circleRadius, startAngle: CGFloat(M_PI), endAngle: CGFloat(M_PI * 2), clockwise: true)
CircleLayer.path = circlePath.cgPath
CircleLayer.strokeColor = UIColor.black.cgColor
//CircleLayer.fillColor = UIColor.blue.cgColor
CircleLayer.lineWidth = 1
CircleLayer.strokeStart = 0
CircleLayer.strokeEnd = 1
object.layer.addSublayer(CircleLayer)
}
Basic Approach
You could do it like this (for the purpose of demonstration, I would do the button programmatically, using a playground):
let buttonWidth = 100.0
let button = UIButton(frame: CGRect(x: 0, y: 0, width: buttonWidth, height: buttonWidth))
button.backgroundColor = .white
button.layer.cornerRadius = button.frame.width / 2
Drawing Part:
So, after adding the button and do the desired setup (make it circular), here is part of how you could draw a circle in it:
let circlePath = UIBezierPath(arcCenter: CGPoint(x: buttonWidth / 2,y: buttonWidth / 2), radius: 40.0, startAngle: 0, endAngle: CGFloat.pi * 2, clockwise: true)
let circleLayer = CAShapeLayer()
circleLayer.path = circlePath.cgPath
circleLayer.fillColor = UIColor.clear.cgColor
circleLayer.strokeColor = UIColor.black.cgColor
circleLayer.lineWidth = 2.5
// adding the layer into the button:
button.layer.addSublayer(circleLayer)
Probably, circleLayer.fillColor = UIColor.clear.cgColor is the part you missing 🙂.
Therefore:
Back to your case:
Aside Bar Tip:
For implementing applyRoundCorner, I would suggest to let it has only the job for rounding the view, and then create another function to add the circle inside the view. And that's for avoiding any naming conflict, which means that when reading "applyRoundCorner" I would not assume that it is also would add circle to my view! So:
func applyRoundedCorners(for view: UIView) {
view.layer.cornerRadius = view.frame.size.width / 2
view.layer.borderColor = UIColor.white.cgColor
view.layer.borderWidth = 5.0
view.layer.masksToBounds = true
}
func drawCircle(in view: UIView) {
let circlePath = UIBezierPath(arcCenter: CGPoint(x: view.frame.size.width / 2,y: view.frame.size.width / 2),
radius: view.frame.size.width / 2.5,
startAngle: 0,
endAngle: CGFloat.pi * 2,
clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = UIColor.black.cgColor
shapeLayer.lineWidth = 2.5
button.layer.addSublayer(shapeLayer)
}
and now:
applyRoundedCorners(for: button)
drawCircle(in: button)
That's seems to be better. From another aspect, consider that you want to make a view to be circular without add a circle in it, with separated methods you could simply applyRoundedCorners(for: myView) without the necessary of adding a circle in it.
Furthermore:
As you can see, I changed AnyObject to UIView, it seems to be more logical to your case. So here is a cool thing that we could do:
extension UIView {
func applyRoundedCorners(for view: UIView) {
view.layer.cornerRadius = view.frame.size.width / 2
view.layer.borderColor = UIColor.white.cgColor
view.layer.borderWidth = 5.0
view.layer.masksToBounds = true
}
func drawCircle(in view: UIView) {
let circlePath = UIBezierPath(arcCenter: CGPoint(x: view.frame.size.width / 2,y: view.frame.size.width / 2),
radius: view.frame.size.width / 2.5,
startAngle: 0,
endAngle: CGFloat.pi * 2,
clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = UIColor.black.cgColor
shapeLayer.lineWidth = 2.5
button.layer.addSublayer(shapeLayer)
}
}
Now both applyRoundedCorners and drawCircle are implicitly included to the UIView (which means UIButton), instead of passing the button to these functions, you would be able to:
button.applyRoundedCorners()
button.drawCircle()
You just need to add circle Shape layer with lesser width and height
Try this code
func applyRoundCorner(_ object: UIButton) {
object.layer.cornerRadius = (object.frame.size.width)/2
object.layer.borderColor = UIColor.black.cgColor
object.layer.borderWidth = 5
object.layer.masksToBounds = true
let anotherFrame = CGRect(x: 12, y: 12, width: object.bounds.width - 24, height: object.bounds.height - 24)
let circle = CAShapeLayer()
let path = UIBezierPath(arcCenter: object.center, radius: anotherFrame.width / 2, startAngle: 0, endAngle: .pi * 2, clockwise: true)
circle.path = path.cgPath
circle.strokeColor = UIColor.black.cgColor
circle.lineWidth = 1.0
circle.fillColor = UIColor.clear.cgColor
object.layer.addSublayer(circle)
}
Note: Change frame value according to your requirements and best user experience
Output
I have no doubt there are a million different ways to approach this problem, this is just one...
I started with a UIButton for simplicity and speed, I might consider actually starting with a UIImage and simply setting the image properties of the button, but it would depend a lot on what I'm trying to achieve
internal extension FloatingPoint {
var degreesToRadians: Self { return self * .pi / 180 }
var radiansToDegrees: Self { return self * 180 / .pi }
}
class RoundButton: UIButton {
override func draw(_ rect: CGRect) {
makeButtonImage()?.draw(at: CGPoint(x: 0, y: 0))
}
func makeButtonImage() -> UIImage? {
let size = bounds.size
UIGraphicsBeginImageContext(CGSize(width: size.width, height: size.height))
defer {
UIGraphicsEndImageContext()
}
guard let ctx = UIGraphicsGetCurrentContext() else {
return nil
}
let center = CGPoint(x: size.width / 2.0, y: size.height / 2.0)
// Want to "over fill" the image area, so the mask can be applied
// to the entire image
let radius = min(size.width / 2.0, size.height / 2.0)
let innerRadius = radius * 0.75
let innerCircle = UIBezierPath(arcCenter: center,
radius: innerRadius,
startAngle: CGFloat(0.0).degreesToRadians,
endAngle: CGFloat(360.0).degreesToRadians,
clockwise: true)
// The color doesn't matter, only it's alpha level
UIColor.red.setStroke()
innerCircle.lineWidth = 4.0
innerCircle.stroke(with: .normal, alpha: 1.0)
let circle = UIBezierPath(arcCenter: center,
radius: radius,
startAngle: CGFloat(0.0).degreesToRadians,
endAngle: CGFloat(360.0).degreesToRadians,
clockwise: true)
UIColor.clear.setFill()
ctx.fill(bounds)
UIColor.white.setFill()
circle.fill(with: .sourceOut, alpha: 1.0)
return UIGraphicsGetImageFromCurrentImageContext()
}
}
nb: This is unoptimised! I would consider caching the result of makeButtonImage and invalidate it when the state/size of the button changes, just beware of that
Why is this approach any "better" then any other? I just want to say, it's not, but what it does create, is a "cut out" of the inner circle
It's a nitpick on my part, but I think it looks WAY better and is a more flexible solution, as you don't "need" a inner circle stroke color, blah, blah, blah
The solution makes use of the CoreGraphics CGBlendModes
Of course I might just do the whole thing in PaintCodeApp and be done with it

iOS: Draw circle as percentage in UIView

I have one UIView in circular shape, I need to show that UIView border colour in percentage value like if percentage value is 50%, it should fill half border colour of UIView. I have used UIBeizer path addArcWithCenter however I didn't get perfect solution. Please help me in this
You can achieve it with following code, simply adjust strokeStart and strokeEnd:
// round view
let roundView = UIView(frame: CGRectMake(100, 100, 250, 250))
roundView.backgroundColor = UIColor.whiteColor()
roundView.layer.cornerRadius = roundView.frame.size.width / 2
// bezier path
let circlePath = UIBezierPath(arcCenter: CGPoint (x: roundView.frame.size.width / 2, y: roundView.frame.size.height / 2),
radius: roundView.frame.size.width / 2,
startAngle: CGFloat(-0.5 * M_PI),
endAngle: CGFloat(1.5 * M_PI),
clockwise: true)
// circle shape
let circleShape = CAShapeLayer()
circleShape.path = circlePath.CGPath
circleShape.strokeColor = UIColor.redColor().CGColor
circleShape.fillColor = UIColor.clearColor().CGColor
circleShape.lineWidth = 1.5
// set start and end values
circleShape.strokeStart = 0.0
circleShape.strokeEnd = 0.8
// add sublayer
roundView.layer.addSublayer(circleShape)
// add subview
self.view.addSubview(roundView)
I've written my custom function for doing this in Swift 5. I'm sure I'll save someone a lot of time. Have fun with it.
func buildRoundView(roundView: UIView, total : Int, current : Int){
roundView.layer.cornerRadius = roundView.frame.size.width / 2
roundView.backgroundColor = .clear
let width :CGFloat = 10.0
let reducer :CGFloat = 0.010
let circlePath = UIBezierPath(arcCenter: CGPoint (x: roundView.frame.size.width / 2, y: roundView.frame.size.height / 2),
radius: roundView.frame.size.width / 2,
startAngle: CGFloat(-0.5 * Double.pi),
endAngle: CGFloat(1.5 * Double.pi),
clockwise: true)
let multiplier = CGFloat((100.000 / Double(total)) * 0.0100)
for i in 1...total {
let circleShape = CAShapeLayer()
circleShape.path = circlePath.cgPath
if i <= current {
circleShape.strokeColor = UIColor.systemRed.cgColor
}
else{
circleShape.strokeColor = UIColor.lightGray.cgColor
}
circleShape.fillColor = UIColor.clear.cgColor
circleShape.lineWidth = width
circleShape.strokeStart = CGFloat(CGFloat(i - 1) * multiplier) + reducer
circleShape.strokeEnd = CGFloat(CGFloat(i) * multiplier) - reducer
roundView.layer.addSublayer(circleShape)
}
}
According #gvuksic's answer:
Swift 5:
// round view
let roundView = UIView(
frame: CGRect(
x: circleContainerView.bounds.origin.x,
y: circleContainerView.bounds.origin.y,
width: circleContainerView.bounds.size.width - 4,
height: circleContainerView.bounds.size.height - 4
)
)
roundView.backgroundColor = .white
roundView.layer.cornerRadius = roundView.frame.size.width / 2
// bezier path
let circlePath = UIBezierPath(arcCenter: CGPoint (x: roundView.frame.size.width / 2, y: roundView.frame.size.height / 2),
radius: roundView.frame.size.width / 2,
startAngle: CGFloat(-0.5 * .pi),
endAngle: CGFloat(1.5 * .pi),
clockwise: true)
// circle shape
let circleShape = CAShapeLayer()
circleShape.path = circlePath.cgPath
circleShape.strokeColor = UIColor.customColor?.cgColor
circleShape.fillColor = UIColor.clear.cgColor
circleShape.lineWidth = 4
// set start and end values
circleShape.strokeStart = 0.0
circleShape.strokeEnd = 0.8
// add sublayer
roundView.layer.addSublayer(circleShape)
// add subview
circleContainerView.addSubview(roundView)
And the result:

custom UIButton with UIBezierPath

I'm making my own custom UIButton.
I subcalssed the UIButton class and drawRect function
this is my code:
override func drawRect(rect: CGRect)
{
let midPoint = CGPointMake(rect.midX, rect.midY)
if !self.selected
{
let redCircle = UIBezierPath()
let redCircleRadius = rect.width - self.whiteCirlceWidth - self.spaceBetweenCirclesWidth
redCircle.addArcWithCenter(CGPointMake(rect.midX, rect.midY), radius: redCircleRadius,
startAngle: 0 , endAngle: 2 * CGFloat(M_PI), clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = redCircle.CGPath
shapeLayer.fillColor = UIColor.redColor().CGColor
shapeLayer.strokeColor = UIColor.blackColor().CGColor
shapeLayer.lineWidth = 4.0
self.layer.addSublayer(shapeLayer)
let whiteCircle = UIBezierPath()
whiteCircle.addArcWithCenter(midPoint,
radius: self.bounds.width / 2,
startAngle: 0, endAngle: 2 * CGFloat(M_PI) , clockwise: true)
UIColor.whiteColor().setFill()
whiteCircle.fill()
}
else
{
let whiteCircle = UIBezierPath()
whiteCircle.addArcWithCenter(midPoint,
radius: self.bounds.width / 2,
startAngle: 0, endAngle: 2 * CGFloat(M_PI) , clockwise: true)
UIColor.whiteColor().setFill()
whiteCircle.fill()
let blankCircle = UIBezierPath()
blankCircle.addArcWithCenter(midPoint, radius: rect.width - self.whiteCirlceWidth - self.spaceBetweenCirclesWidth,
startAngle: 0, endAngle: 2 * CGFloat(M_PI), clockwise: true)
UIColor.blackColor().setFill()
blankCircle.fill()
var rect = CGRect(origin: midPoint, size: CGSizeMake(rect.width / 2, rect.width / 2))
rect.origin.x -= rect.origin.x / 2
rect.origin.y -= rect.origin.y / 2
let roundedRect = UIBezierPath(roundedRect: rect, cornerRadius: 3)
UIColor.redColor().setFill()
roundedRect.fill()
}
}
when I click on the button I do this
#IBAction func recordBtnClicked(sender : UIButton)
{
self.recordBtn.selected = !self.recordBtn.selected
self.recordBtn.setNeedsDisplay()
}
but it doesn't change anything!.
I checked in the debugger and it does the right block of code .
I checked two blocks and they do the right drawing
what's wrong?
I figured it out it was because I added a subLayer and it stucks and I didn't remove it ' so I changed the code and didn't used the sublayer.
you can remove the subLayer each time you call drawRect

How to create rounded corners with CAShapeLayer

Is there a way to add rounded corners to a CAShapeLayer? In my case I needed the shape layer to create a dashed border via lineDashPattern.
^ notice how the dashed line is not rounded
The answer is simple. Create a bézier path with rounded corners.
UPDATE for Swift
view.clipsToBounds = true
view.layer.cornerRadius = 10.0
let border = CAShapeLayer()
border.path = UIBezierPath(roundedRect:view.bounds, cornerRadius:10.0).cgPath
border.frame = view.bounds
border.fillColor = nil
border.strokeColor = UIColor.purple.cgColor
border.lineWidth = borderWidth * 2.0 // doubled since half will be clipped
border.lineDashPattern = [15.0]
view.layer.addSublayer(border)
Objective-C
// (This old code assumes this is within a view with a custom property "border".)
self.clipsToBounds = YES;
self.layer.cornerRadius = 10.0;
self.border = [CAShapeLayer layer];
self.border.fillColor = nil;
self.border.path = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:10.0].cgPath;
self.border.frame = self.bounds;
self.border.strokeColor = [UIColor purpleColor].CGColor;
self.border.lineWidth = borderWidth * 2; // double desired width as half will be clipped
self.border.lineDashPattern = #[#15];
[self.layer addSublayer:self.border];
In swift 4 I created a UIView category (UIView+Borders) with the following function:
func borderDash(withRadius cornerRadius: Float, borderWidth: Float, borderColor: UIColor, dashSize: Int) {
let currentFrame = self.bounds
let shapeLayer = CAShapeLayer()
let path = CGMutablePath()
let radius = CGFloat(cornerRadius)
// Points - Eight points that define the round border. Each border is defined by two points.
let topLeftPoint = CGPoint(x: radius, y: 0)
let topRightPoint = CGPoint(x: currentFrame.size.width - radius, y: 0)
let middleRightTopPoint = CGPoint(x: currentFrame.size.width, y: radius)
let middleRightBottomPoint = CGPoint(x: currentFrame.size.width, y: currentFrame.size.height - radius)
let bottomRightPoint = CGPoint(x: currentFrame.size.width - radius, y: currentFrame.size.height)
let bottomLeftPoint = CGPoint(x: radius, y: currentFrame.size.height)
let middleLeftBottomPoint = CGPoint(x: 0, y: currentFrame.size.height - radius)
let middleLeftTopPoint = CGPoint(x: 0, y: radius)
// Points - Four points that are the center of the corners borders.
let cornerTopRightCenter = CGPoint(x: currentFrame.size.width - radius, y: radius)
let cornerBottomRightCenter = CGPoint(x: currentFrame.size.width - radius, y: currentFrame.size.height - radius)
let cornerBottomLeftCenter = CGPoint(x: radius, y: currentFrame.size.height - radius)
let cornerTopLeftCenter = CGPoint(x: radius, y: radius)
// Angles - The corner radius angles.
let topRightStartAngle = CGFloat(Double.pi * 3 / 2)
let topRightEndAngle = CGFloat(0)
let bottomRightStartAngle = CGFloat(0)
let bottmRightEndAngle = CGFloat(Double.pi / 2)
let bottomLeftStartAngle = CGFloat(Double.pi / 2)
let bottomLeftEndAngle = CGFloat(Double.pi)
let topLeftStartAngle = CGFloat(Double.pi)
let topLeftEndAngle = CGFloat(Double.pi * 3 / 2)
// Drawing a border around a view.
path.move(to: topLeftPoint)
path.addLine(to: topRightPoint)
path.addArc(center: cornerTopRightCenter,
radius: radius,
startAngle: topRightStartAngle,
endAngle: topRightEndAngle,
clockwise: false)
path.addLine(to: middleRightBottomPoint)
path.addArc(center: cornerBottomRightCenter,
radius: radius,
startAngle: bottomRightStartAngle,
endAngle: bottmRightEndAngle,
clockwise: false)
path.addLine(to: bottomLeftPoint)
path.addArc(center: cornerBottomLeftCenter,
radius: radius,
startAngle: bottomLeftStartAngle,
endAngle: bottomLeftEndAngle,
clockwise: false)
path.addLine(to: middleLeftTopPoint)
path.addArc(center: cornerTopLeftCenter,
radius: radius,
startAngle: topLeftStartAngle,
endAngle: topLeftEndAngle,
clockwise: false)
// Path is set as the shapeLayer object's path.
shapeLayer.path = path;
shapeLayer.backgroundColor = UIColor.clear.cgColor
shapeLayer.frame = currentFrame
shapeLayer.masksToBounds = false
shapeLayer.setValue(0, forKey: "isCircle")
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = borderColor.cgColor
shapeLayer.lineWidth = CGFloat(borderWidth)
shapeLayer.lineDashPattern = [NSNumber(value: dashSize), NSNumber(value: dashSize)]
shapeLayer.lineCap = kCALineCapRound
self.layer.addSublayer(shapeLayer)
self.layer.cornerRadius = radius;
}

Resources