How to set layer cornerRadius for only bottom-left, bottom-right, and top-left corner?
SwiftTextviewRounded CornersSwift Problem Overview
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.
Swift Solutions
Solution 1 - Swift
(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 :)
Solution 2 - Swift
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
Solution 3 - Swift
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)
Solution 4 - Swift
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
}
Solution 5 - Swift
Swift 4+
func roundCorners(with CACornerMask: CACornerMask, radius: CGFloat) {
self.layer.cornerRadius = radius
self.layer.maskedCorners = [CACornerMask]
}
Top right
roundCorners(with: [.layerMinXMinYCorner], radius: 20)
Top left
roundCorners(with: [.layerMaxXMinYCorner], radius: 20)
Bottom right
roundCorners(with: [.layerMinXMaxYCorner], radius: 20)
Bottom left
roundCorners(with: [.layerMaxXMaxYCorner], radius: 20)
OR
Multiple corners at the same time
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)
Solution 6 - Swift
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 :
extension on UIView Swift 4 : Reference Link
Solution 7 - Swift
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]
Solution 8 - Swift
For subview & POPUPs [Swift 5]
override func layoutSublayers(of layer: CALayer) {
searchBarPopup.clipsToBounds = true
searchBarPopup.layer.cornerRadius = 10
searchBarPopup.layer.maskedCorners = [ .layerMaxXMinYCorner, .layerMinXMinYCorner]
}
output:
Solution 9 - Swift
-
Add RoundedCornerView.swift file to your project
-
Add an UIView to your ViewController
-
Change Custom Class in Identity Inspector to RoundedCornerView
-
Go to Attribute Inspector pick Corner Radius (CGFloat) and On the corners you want rounded.
> 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
Solution 10 - Swift
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)
Solution 11 - Swift
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
}
}
}
Solution 12 - Swift
> 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
}
}
}