Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's currently the "correct" way to set a UIView's corner radius?

Tags:

ios

swift

uiview

Setting a UIView's corner radius can be done the following ways:

  1. Set the layer's cornerRadius property:

    view.layer.cornerRadius = 5;
    view.layer.masksToBounds = true;
    
  2. 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
    }
    
  3. 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)
like image 560
GoldenJoe Avatar asked Jun 18 '17 05:06

GoldenJoe


People also ask

How do you set corner radius for UIView in storyboard?

Select the view that you want to round and open its Identity Inspector. In the User Defined Runtime Attributes section, add the following two entries: Key Path: layer. cornerRadius , Type: Number, Value: (whatever radius you want)

How do I change my corner radius to UIView?

If you start with a regular UIView it has square corners. You can give it round corners by changing the cornerRadius property of the view's layer . and smaller values give less rounded corners. Both clipsToBounds and masksToBounds are equivalent.

How do you round the top corner of UIView in Swift?

You can set the cornerRadius property of any UIView to have its edges rounded, but by default that rounds all corners at the same time.


2 Answers

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:

top-left and top-right corner of a UIView

like image 145
Bruno Bieri Avatar answered Oct 12 '22 09:10

Bruno Bieri


Re your three options:

  1. 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.

  2. 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.

  3. 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.

like image 31
Rob Avatar answered Oct 12 '22 09:10

Rob