Reputation: 8012
Setting a UIView
's corner radius can be done the following ways:
Set the layer
's cornerRadius
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:
cornerRadius
changing)Upvotes: 19
Views: 12644
Reputation: 103
contView.layer.cornerRadius = 25
contView.layer.maskedCorners = [.layerMaxXMinYCorner,.layerMinXMinYCorner]
contView.layer.masksToBounds = true
this is the result just top left and top right corners
Upvotes: 0
Reputation: 10256
Note that I don't know what's currently the “correct” way to set a UIView's corner radius.
What I prefer to do is to use Interface Builder as much as possible without having extra code which this approach shows and is reliable to my experience.
From iOS 11 upwards
you can use user-defined runtime attributes in the Identity inspector
of the Interface Builder
by setting the following properties:
layer.cornerRadius
layer.maskedCorners
layer.masksToBounds
According to the documentation of the CACornerMask you can see that the maskedCorners
property is in fact a NSUInteger
data type and you're allowed to set the following values:
kCALayerMinXMinYCorner = 1U << 0
kCALayerMaxXMinYCorner = 1U << 1
kCALayerMinXMaxYCorner = 1U << 2
kCALayerMaxXMaxYCorner = 1U << 3
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:
0 = no corner is being rounded
1 = top left corner rounded only
2 = top right corner rounded only
3 = top left and top right corners rounded only
4 = bottom left corner rounded only
5 = top left and bottom left corners rounded only
6 = top right and bottom left corners rounded only
7 = top left, top right and bottom left corners rounded only
8 = bottom right corner rounded only
9 = top left and bottom right corners rounded only
10 = top right and bottom right corners rounded only
11 = top left, top right and bottom right corners rounded only
12 = bottom left and bottom right corners rounded only
13 = top left, bottom left and bottom right corners rounded only
14 = top right, bottom left and bottom right corners rounded only
15 = all corners rounded
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:
Upvotes: 18
Reputation: 438232
Re your three options:
Using CALayer
existing properties: This is an easy (and likely the most efficient) solution for simple corner masking. It is animatable, too. In iOS 11 and later, you can pick which corners are to be masked.
Re custom CAShapeLayer
masks: This is nice approach if the corner masking is not simple corner rounding but some arbitrary path. You have to be cautious to make sure to update this mask if the frame
changes (e.g. update the path in layoutSubviews
of view or in viewDidLayoutSubviews
of controller).
Admittedly, if you want to do a very graceful animation as the view’s frame
changes, that takes a little more work. But, as I point out above, simply responding to frame changes in layoutSubviews
or viewDidLayoutSubviews
is quite simple and takes care of it if you are not too worried about the corner rounding mid-animation.
Re custom draw(_:)
: This is more work than it is worth and you are probably not enjoying optimizations that Apple’s team may have done behind the scenes (e.g. what if subsequent draw
calls are only drawing a portion of the full bounds
; your code is redrawing the whole thing regardless).
I would 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 are willing to go through.
Upvotes: 10
Reputation: 1013
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.
// Full size
CGSize vSize = [UIScreen mainScreen].bounds.size;
// Object
UIView *viewTest = [[UIView alloc] initWithFrame: CGRectMake(0, 0, vSize.width, vSize.height)];
[viewTest setAutoresizingMask: UIViewAutoresizingFlexibleHeight];
[viewTest setBackgroundColor: [UIColor grayColor]];
// maskedCorners is only available in iOS 11
if (@available(iOS 11.0, *)) {
[viewTest setClipsToBounds: YES];
[viewTest.layer setCornerRadius: 10];
// Only if you want to round the left and right top corners
[viewTest.layer setMaskedCorners: kCALayerMinXMinYCorner | kCALayerMaxXMinYCorner];
}
else {
// The old way used in lower version
CAShapeLayer *shapeLayerObj = [CAShapeLayer layer];
[shapeLayerObj setPath: [UIBezierPath bezierPathWithRoundedRect: viewTest.bounds byRoundingCorners: UIRectCornerTopLeft | UIRectCornerTopRight cornerRadii: (CGSize){10.0, 10.}].CGPath];
[viewTest.layer setMask: shapeLayerObj];
}
The swift version it's something like this
let view = UIView()
view.clipsToBounds = true
view.layer.cornerRadius = 8
view.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner]
Upvotes: 9
Reputation: 467
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.
Upvotes: 8
Reputation: 5449
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:
Upvotes: 1