How to set layer cornerRadius for only bottom-left, bottom-right, and top-left corner?

How to set corner radius only only bottom-left, bottom-right, and top-left corners of a textview?

let rectShape = CAShapeLayer()
rectShape.backgroundColor = UIColor.redColor().CGColor
rectShape.bounds = messages.frame
rectShape.position = messages.center
rectShape.path = UIBezierPath(roundedRect: messages.bounds, byRoundingCorners: .BottomLeft | .TopRight, cornerRadii: CGSize(width: 20, height: 20)).CGPath


messages.layer.addSublayer(rectShape)

this code creates two rects. I dont know why.

104842 次浏览

You just need to mask the layer as shown below:

For Swift 3:

let rectShape = CAShapeLayer()
rectShape.bounds = self.myView.frame
rectShape.position = self.myView.center
rectShape.path = UIBezierPath(roundedRect: self.myView.bounds, byRoundingCorners: [.bottomLeft , .bottomRight , .topLeft], cornerRadii: CGSize(width: 20, height: 20)).cgPath


self.myView.layer.backgroundColor = UIColor.green.cgColor
//Here I'm masking the textView's layer with rectShape layer
self.myView.layer.mask = rectShape

Lower Version:

let rectShape = CAShapeLayer()
rectShape.bounds = self.myView.frame
rectShape.position = self.myView.center
rectShape.path = UIBezierPath(roundedRect: self.myView.bounds, byRoundingCorners: .BottomLeft | .BottomRight | .TopLeft, cornerRadii: CGSize(width: 20, height: 20)).CGPath


self.myView.layer.backgroundColor = UIColor.greenColor().CGColor
//Here I'm masking the textView's layer with rectShape layer
self.myView.layer.mask = rectShape

Swift 3

extension UIView {
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
}
}

Use like this

YourView.roundCorners([.topLeft, .bottomLeft], radius: 10)

(swift 4/iOS 11) Just simply say for bottom:

yourView.clipsToBounds = true
yourView.layer.cornerRadius = 10
yourView.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner]

for Up:

yourView.clipsToBounds = true
yourView.layer.cornerRadius = 10
yourView.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner]

in your case:

yourView.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner, .layerMinXMinYCorner]

Hope this help :)

A better answer for both iOS 11 and iOS 10 bottom corner would be

 if #available(iOS 11.0, *){
view.clipsToBounds = true
view.layer.cornerRadius = 10
view.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner]
}else{
let rectShape = CAShapeLayer()
rectShape.bounds = view.frame
rectShape.position = view.center
rectShape.path = UIBezierPath(roundedRect: view.bounds,    byRoundingCorners: [.bottomLeft , .bottomRight], cornerRadii: CGSize(width: 20, height: 20)).cgPath
view.layer.backgroundColor = UIColor.green.cgColor
view.layer.mask = rectShape
}

in case this didnt work on iOS 10 and below, try running the code in viewDidLayoutSubviews() of your viewcontroller class like this

override func viewDidLayoutSubviews() {
if #available(iOS 11.0, *){
}else{
let rectShape = CAShapeLayer()
rectShape.bounds = view.frame
rectShape.position = view.center
rectShape.path = UIBezierPath(roundedRect: view.bounds,    byRoundingCorners: [.bottomLeft , .bottomRight], cornerRadii: CGSize(width: 20, height: 20)).cgPath
view.layer.backgroundColor = UIColor.green.cgColor
view.layer.mask = rectShape
}

issue solved right top and right bottom work now

Tested code in iOS 9 , 10 , 11 version

 extension UIView {
func roundCorners(_ corners:UIRectCorner,_ cormerMask:CACornerMask, radius: CGFloat) {
if #available(iOS 11.0, *){
self.clipsToBounds = false
self.layer.cornerRadius = radius
self.layer.maskedCorners = cormerMask
}else{
let rectShape = CAShapeLayer()
rectShape.bounds = self.frame
rectShape.position = self.center
rectShape.path = UIBezierPath(roundedRect: self.bounds,    byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius)).cgPath
self.layer.mask = rectShape
}
}
        

}

Swift 4

override func viewDidLoad() {
let topRight = UIView(frame: CGRect(x: 120, y: 200, width: 120, height: 120))
topRight.roundedTop()
topRight.backgroundColor = .red
self.view.center = topRight.center
self.view.addSubview(topRight)
super.viewDidLoad()
}

Output :

enter image description here

extension on UIView Swift 4 : Reference Link

Here is an extension for iOS 11+

 import Foundation
import UIKit


extension UIView {


func roundCorners(_ corners: CACornerMask, radius: CGFloat, borderColor: UIColor, borderWidth: CGFloat) {
self.layer.maskedCorners = corners
self.layer.cornerRadius = radius
self.layer.borderWidth = borderWidth
self.layer.borderColor = borderColor.cgColor
    

}


}

Usage:-

self.yourView.roundCorners([.layerMaxXMaxYCorner, .layerMaxXMinYCorner], radius: 20.0, borderColor: UIColor.green, borderWidth: 1)

Swift 5+

view.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMaxXMinYCorner]
  1. Add RoundedCornerView.swift file to your project
  2. Add an UIView to your ViewController
  3. Change Custom Class in Identity Inspector to RoundedCornerView
  4. Go to Attribute Inspector pick Corner Radius (CGFloat) and On the corners you want rounded.

rounded corner view

RoundedCornerView.swift

import UIKit


@IBDesignable
class RoundedCornerView: UIView {


var cornerRadiusValue : CGFloat = 0
var corners : UIRectCorner = []


@IBInspectable public var cornerRadius : CGFloat {
get {
return cornerRadiusValue
}
set {
cornerRadiusValue = newValue
}
}


@IBInspectable public var topLeft : Bool {
get {
return corners.contains(.topLeft)
}
set {
setCorner(newValue: newValue, for: .topLeft)
}
}


@IBInspectable public var topRight : Bool {
get {
return corners.contains(.topRight)
}
set {
setCorner(newValue: newValue, for: .topRight)
}
}


@IBInspectable public var bottomLeft : Bool {
get {
return corners.contains(.bottomLeft)
}
set {
setCorner(newValue: newValue, for: .bottomLeft)
}
}


@IBInspectable public var bottomRight : Bool {
get {
return corners.contains(.bottomRight)
}
set {
setCorner(newValue: newValue, for: .bottomRight)
}
}


func setCorner(newValue: Bool, for corner: UIRectCorner) {
if newValue {
addRectCorner(corner: corner)
} else {
removeRectCorner(corner: corner)
}
}


func addRectCorner(corner: UIRectCorner) {
corners.insert(corner)
updateCorners()
}


func removeRectCorner(corner: UIRectCorner) {
if corners.contains(corner) {
corners.remove(corner)
updateCorners()
}
}


func updateCorners() {
let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: cornerRadiusValue, height: cornerRadiusValue))
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
}


}

github link : RoundedCornerView

extension UIView {


func roundCorners(_ corners: CACornerMask, radius: CGFloat) {
if #available(iOS 11, *) {
self.layer.cornerRadius = radius
self.layer.maskedCorners = corners
} else {
var cornerMask = UIRectCorner()
if(corners.contains(.layerMinXMinYCorner)){
cornerMask.insert(.topLeft)
}
if(corners.contains(.layerMaxXMinYCorner)){
cornerMask.insert(.topRight)
}
if(corners.contains(.layerMinXMaxYCorner)){
cornerMask.insert(.bottomLeft)
}
if(corners.contains(.layerMaxXMaxYCorner)){
cornerMask.insert(.bottomRight)
}
let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: cornerMask, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
}
}

}

For subview & POPUPs [Swift 5]

override func layoutSublayers(of layer: CALayer) {
searchBarPopup.clipsToBounds = true
searchBarPopup.layer.cornerRadius = 10
searchBarPopup.layer.maskedCorners = [ .layerMaxXMinYCorner, .layerMinXMinYCorner]
}

output:

enter image description here

Swift 4+

func roundCorners(with CACornerMask: CACornerMask, radius: CGFloat) {
self.layer.cornerRadius = radius
self.layer.maskedCorners = [CACornerMask]
}

How to use

//Top right
roundCorners(with: [.layerMaxXMinYCorner], radius: 20)


//Top left
roundCorners(with: [.layerMinXMinYCorner], radius: 20)


//Bottom right
roundCorners(with: [.layerMaxXMaxYCorner], radius: 20)


//Bottom left
roundCorners(with: [.layerMinXMaxYCorner], radius: 20)

OR

Another way using CACornerMask

extension UIView{
    

enum RoundCornersAt{
case topRight
case topLeft
case bottomRight
case bottomLeft
}
    

//multiple corners using CACornerMask
func roundCorners(corners:[RoundCornersAt], radius: CGFloat) {
self.layer.cornerRadius = radius
self.layer.maskedCorners = [
corners.contains(.topRight) ? .layerMaxXMinYCorner:.init(),
corners.contains(.topLeft) ? .layerMinXMinYCorner:.init(),
corners.contains(.bottomRight) ? .layerMaxXMaxYCorner:.init(),
corners.contains(.bottomLeft) ? .layerMinXMaxYCorner:.init(),
]
}
    

}

You can use like below

myView.roundCorners(corners: [.topLeft,.bottomLeft], radius: 20)

OR

Multiple corners using UIRectCorner

func roundedCorners(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
layer.mask = mask
}

How to use

roundedCorners(corners: [.topLeft, .topRight], radius: 20)

The best solution I could come up with all of the above solution is this.

extension UIView {
func roundCorners(_ corners: UIRectCorner, radius: CGFloat) {
if #available(iOS 11, *) {
var cornerMask = CACornerMask()
if(corners.contains(.topLeft)){
cornerMask.insert(.layerMinXMinYCorner)
}
if(corners.contains(.topRight)){
cornerMask.insert(.layerMaxXMinYCorner)
}
if(corners.contains(.bottomLeft)){
cornerMask.insert(.layerMinXMaxYCorner)
}
if(corners.contains(.bottomRight)){
cornerMask.insert(.layerMaxXMaxYCorner)
}
self.layer.cornerRadius = radius
self.layer.maskedCorners = cornerMask


} else {
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
}
}
}

I believe that this way the implementation is easy while selecting the sides.

view.roundCorners([.bottomLeft, .bottomRight, .topLeft], radius: 16)

As @kazi.munshimun gave a view-only setup suggestion, it is wonderful, however I didn't want create a whole view for this, and I was looking for a one-only field for cornerRadius.

So I came up with the idea of flag combinations where for example BottomLeft(4) + BottomRight(8) = 12

Therefore, it needs on your view to set up the number combination from 0 (none) to 15 (all of corners) + clipsToBounds enabled. And that's it ! Entirely customizable through file.

This solution example works for iOS 11.0+ (Swift 4+) It can be adapted for lower versions :

extension UIView {
enum CornerEnum: Int  {
case None = 0
case TopLeft = 1
case TopRight = 2
case BottomLeft = 4
case BottomRight = 8
}
    

@IBInspectable
var radiusCorners: Int {
set {
var corners = CACornerMask()
if(newValue & CornerEnum.TopLeft.rawValue != 0){
corners.insert(.layerMinXMinYCorner)
}
if(newValue & CornerEnum.TopRight.rawValue != 0){
corners.insert(.layerMaxXMinYCorner)
}
if(newValue & CornerEnum.BottomLeft.rawValue != 0){
corners.insert(.layerMinXMaxYCorner)
}
if(newValue & CornerEnum.BottomRight.rawValue != 0){
corners.insert(.layerMaxXMaxYCorner)
}
layer.maskedCorners = corners
}
get { return self.radiusCorners }
}
}