Setting a UIView
's corner radius can be done the following ways:
Set the
layer
'scornerRadius
property:view.layer.cornerRadius = 5; view.layer.masksToBounds = true;
Apply a mask:
func roundCorners(corners:UIRectCorner, radius: CGFloat) { let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius)) let mask = CAShapeLayer() mask.path = path.cgPath self.layer.mask = mask }
Override
draw(_:)
:func draw(_ rect: CGRect) { // Size of rounded rectangle let rectWidth = rect.width let rectHeight = rect.height // Find center of actual frame to set rectangle in middle let xf: CGFloat = (self.frame.width - rectWidth) / 2 let yf: CGFloat = (self.frame.height - rectHeight) / 2 let ctx = UIGraphicsGetCurrentContext()! ctx.saveGState() let rect = CGRect(x: xf, y: yf, width: rectWidth, height: rectHeight) let clipPath = UIBezierPath(roundedRect: rect, cornerRadius: rectCornerRadius).cgPath ctx.addPath(clipPath) ctx.setFillColor(rectBgColor.cgColor) ctx.closePath() ctx.fillPath() ctx.restoreGState() }
Which of these is generally considered to be the "correct" way of implementing rounded corners on a UIView
, accounting for the following criteria:
- configuration (some corners may be rounded while others are not)
- animation (can you animate the
cornerRadius
changing) - flexibility (does it break third party libraries or masks you have already applied)
- readability (how concise/reusable is the solution)
- speed (does it negatively impact performance)
I did a couple of test with iOS 11 or lower version and the best practice I discovered for me to round a specific or all corners, you can do with the next code.
The swift version it's something like this
I think this is the most comprehensive summary of all: http://texturegroup.org/docs/corner-rounding.html
My heuristic is that if the view doesn't need a high performance (e.g. it's not inside a table view cell), the easiest option is using CALayer's
cornerRadius
. If you need some more advanced corner radius or high performance, then it's better to explore other options.From iOS 11 upwards
you can use user-defined runtime attributes in the
Identity inspector
of theInterface Builder
by setting the following properties:According to the documentation of the CACornerMask you can see that the
maskedCorners
property is in fact aNSUInteger
data type and you're allowed to set the following values:Since you're allowed to
bitwise OR
those masks together you only have to "calculate" the resulting integer of that bitwise OR of what you actually need.Therefore set the following number (integer) values for the
maskedCorners
property to get rounded corners:Example: If you want to set the corner radius for the top-left and the top-right corners of a UIView you would use those attributes:
Re your three options:
Using
CALayer
existing properties: This is an easy (and likely the most efficient) solution for simple corner masking. It's animatable, too. In iOS 11, you can pick the masked corners.Re custom
CAShapeLayer
masks: This is nice approach if the corner masking isn't simple corner rounding but some arbitrary path. You have to be cautious to make sure to update this mask if theframe
changes (e.g. inlayoutSubviews
of view or inviewDidLayoutSubviews
of controller). Animating requires more work.Re custom
draw(_:)
: This is more work than its worth and you're probably not enjoying optimizations that Apple's team may have done behind the scenes (e.g. what if subsequentdraw
calls are only drawing a portion of the fullbounds
; your code is redrawing the whole thing regardless).I'd suggest option 1 for simple cases, and option 2 if you need more control than option 1 can offer. But there is no "best" approach: It depends upon what you need and how much work you're willing to go through.
I go with the first one, it is the cleaner way of doing and you can do it in the IDE without code. Open the attributes inspector and then click on the Identity inspector and add under "User Defined Runtime attributes" those 2 properties: