29

How can I create a UIButton with rounded corners that are smooth? The standard apple rounded corners are much nicer than the standard rounded corners. If I design a button in sketch, I can toggle "smooth corners" which toggles the corners of a shape from Apple rounded corners (smooth) to standard rounded corners.

Here is a comparison:

enter image description here

How can I toggle this in swift?

showContentButton.layer.cornerRadius = 20 rounds the corners, however, I don't really know if this rounded corners are "smooth corners" or "standard rounded corners". And I don't know how to toggle this. Any ideas?

WalterBeiter
  • 2,021
  • 3
  • 23
  • 48

4 Answers4

39

Starting iOS 13.0, you can just use this property in addition to setting the cornerRadius:

sampleButton.layer.cornerCurve = .continuous

This is also easily animatable, which previously resulted in problems using a UIBezierPath.

See more at https://developer.apple.com/documentation/quartzcore/calayer/3152596-cornercurve

Vincent Friedrich
  • 1,027
  • 1
  • 8
  • 11
29

Prior to iOS 13

To get that effect you can use UIBezierPath

Smooth corners

Edit: Usage in UIView

class MyView: UIView {

    let myButton UIButton = UIButton()

    override func layoutSubviews() {
        super.layoutSubviews()

        // your roundPath code here
    }

}

Edit 2:

Use this approach for rounding specific corners:

let roundPath = UIBezierPath(
    roundedRect: bounds,
    byRoundingCorners: [.topLeft, .topRight],
    cornerRadii: CGSize(width: 10, height: 10)
)

Source

inokey
  • 5,434
  • 4
  • 21
  • 33
  • the button disappeared completely. I did: `let smoothCornersRoundedPath = UIBezierPath(roundedRect: bounds, cornerRadius: 8) let maskLayer = CAShapeLayer() maskLayer.path = smoothCornersRoundedPath.cgPath showContentButton.layer.mask = maskLayer` – WalterBeiter Sep 13 '18 at 09:54
  • 1
    did you do that in `layoutSubviews` method? – inokey Sep 13 '18 at 09:56
  • my button is inside a UIView class. – WalterBeiter Sep 13 '18 at 11:30
  • 1
    The button has only one rounded corner. But it seems like it is a smooth corner. But all other three corners are sharp (90°) – WalterBeiter Sep 13 '18 at 12:02
  • It just doesn't fit the rect of your view. Try adding some constraints first or however you do the layout. – inokey Sep 13 '18 at 12:04
  • it no works: `let smoothCornersRoundedPath = UIBezierPath(roundedRect: showContentButton.bounds, cornerRadius: 8)`. I had to add `showContenButton.bounds` instead of just `bounds`. – WalterBeiter Sep 13 '18 at 12:13
  • Well of course. You apply corner radius to your button and not to the superview. – inokey Sep 13 '18 at 12:16
  • 1
    one last question: How can I restrict the corner radius to specific corners? For instance: the top right and bottom right corner should be rounded, but the top left and bottom left corners should be sharp. – WalterBeiter Sep 14 '18 at 13:34
  • @WalterBeiter I know it's been a while but can you please accept the answer? :) – inokey Dec 25 '18 at 04:54
  • this answer works and solved my question, however the answer from @Vincent Friedrich is definitely better if you are on iOS 13 or above – WalterBeiter Jan 31 '20 at 08:03
  • 3
    @WalterBeiter thanks! I've aded memo that my solution goes prior to iOS 13. – inokey Jan 31 '20 at 08:50
3

Just use this extension

extension CALayer {

   func roundCorners(radius: CGFloat) {
       let roundPath = UIBezierPath(
           roundedRect: self.bounds,
           cornerRadius: radius)
       let maskLayer = CAShapeLayer()
       maskLayer.path = roundPath.cgPath
       self.mask = maskLayer
   }

}

and use it like this

cell.layer.roundCorners(radius: 18)
enigrify
  • 281
  • 3
  • 17
  • you can't add a CALayer like that. when you add a CALayer, you need to update the frame in `layoutSubviews` every time `layoutSubviews` is called (this is the whole purpose of layoutSubviews) – Fattie Mar 09 '23 at 16:36
3

For SwiftUI, you can try this:

.clipShape(RoundedRectangle(cornerRadius: 8, style: .continuous))

Example:

Rectangle()
    .clipShape(RoundedRectangle(cornerRadius: 24, style: .continuous))
    .padding()

or use extension:

extension View {
    func smoothCornerRadius(_ x: CGFloat) -> some View {
        return self
            .clipShape(RoundedRectangle(cornerRadius: x, style: .continuous))
    }
}

Result here

Nhat Nguyen Duc
  • 432
  • 2
  • 10
  • I believe Nhat Nguyen Duc should be bountied. Because his answer is the most Swifty available here. And it's not bounded to any global property change. – Allan Garcia Mar 12 '23 at 13:35