How to set layer cornerRadius for only bottom-left, bottom-right, and top-left corner? - swift
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 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 :)
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)
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
}
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)
For subview & POPUPs [Swift 5]
override func layoutSublayers(of layer: CALayer) {
searchBarPopup.clipsToBounds = true
searchBarPopup.layer.cornerRadius = 10
searchBarPopup.layer.maskedCorners = [ .layerMaxXMinYCorner, .layerMinXMinYCorner]
}
output:
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 :
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]
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
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)
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
}
}
}
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
}
}
}
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 }
}
}
Related
can't make round corners for UIView
I have a UIView object inside a horizontal stackView. I'm calling this function inside LayoutSubviews: func roundCorners(corners: UIRectCorner, radius: CurveRadius) { var r = CGFloat() switch radius { case .small: r = self.frame.width / 30 case .medium: r = self.frame.width / 25 } let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: r, height: r)) let mask = CAShapeLayer() mask.path = path.cgPath layer.mask = mask } but it just doesn't work. I guess it has something to do with a stackView. can anyone help me out?
extension UIView { /// Rounds ``UIView`` corners. /// - Parameters: /// - maskedCorners: Corners to be rounded. /// - cornerRadius: Value to be set as corner radius. func roundCorners(maskedCorners: CACornerMask, cornerRadius: CGFloat) { layer.cornerRadius = cornerRadius layer.maskedCorners = maskedCorners layer.masksToBounds = true } }
I'm not sure if the UIStackView is the problem here, but there's another, more re-usable way to do this using a CACornerMask on the UIView's layer in an extension: extension UIView { func roundCorners() { self.layer.cornerRadius = 10 self.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMaxXMinYCorner] } } When you create your view, just call the roundCorners(), like this: private lazy var roundCorneredView: UIView = { let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100)) view.backgroundColor = .red view.roundCorners() view.translatesAutoresizingMaskIntoConstraints = false return view }() Then add that view to your hierarchy in the usual way using addSubview. CACornerMask docs # Apple
Custom UIButton Causes Storyboard Agent Crash Swift
I created a custom UIButton class and it causing the storyboard agent to fail. I'm Including my extensions cause I really don't know what the problem is. I tried to debug this view from the storyboard but it sends me straight to assembly code. I tried to make it a without #IBDesignable, but it still cause a crash. Also if you tips for improving how I'm writing my class I'll be glad to hear them. I'll be glad if you can help me This is my class: #IBDesignable class customButton: UIButton{ private let imagesPadding: CGFloat = 2 private var ArrowSymbleImageView: UIImageView! #IBInspectable var iconImageInspectable: UIImage = UIImage(systemName: "globe")!{ willSet { if (ArrowSymbleImageView != nil) { ArrowSymbleImageView.image = newValue } } } #IBInspectable var BackgroundColorInspectable: UIColor = .white { willSet { self.backgroundColor = newValue if (ArrowSymbleImageView != nil) { if (self.BackgroundColorInspectable.isDarkColor) { ArrowSymbleImageView.tintColor = .white }else{ ArrowSymbleImageView.tintColor = .black } } } } required init?(coder: NSCoder) { super.init(coder: coder) self.generalInit() } private func generalDeinit() { ArrowSymbleImageView.removeFromSuperview() } private func generalInit() { self.backgroundColor = self.BackgroundColorInspectable self.roundCorners(corners: [.bottomLeft], radius: self.width() / 2 * 0.7) self.dropShadow() let sizePartFromView: CGFloat = 4 ArrowSymbleImageView = UIImageView(frame: CGRect(x: self.width() / 2 - (self.width() / sizePartFromView / 2), y: self.height() / 2 - (self.height() / sizePartFromView / 2), width: self.width() / sizePartFromView, height: self.height() / sizePartFromView)) ArrowSymbleImageView.image = self.iconImageInspectable if (self.BackgroundColorInspectable.isDarkColor) { ArrowSymbleImageView.tintColor = .white }else{ ArrowSymbleImageView.tintColor = .black } ArrowSymbleImageView.contentMode = .scaleAspectFill self.addSubview(ArrowSymbleImageView) } } internal extension UIView { func roundCorners(corners: UIRectCorner, radius: CGFloat) { let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius)) let mask = CAShapeLayer() mask.path = path.cgPath layer.mask = mask } } internal extension UIView { func dropShadow(scale: Bool = true, size: CGSize = CGSize(width: -2, height: 2)) { layer.masksToBounds = false layer.shadowColor = UIColor.black.cgColor layer.shadowOpacity = 0.5 layer.shadowOffset = size layer.shadowRadius = 1 layer.shadowPath = UIBezierPath(rect: bounds).cgPath layer.shouldRasterize = true layer.rasterizationScale = scale ? UIScreen.main.scale : 1 } func dropShadow(color: UIColor, opacity: Float = 0.5, offSet: CGSize, radius: CGFloat = 1, scale: Bool = true) { layer.masksToBounds = false layer.shadowColor = color.cgColor layer.shadowOpacity = opacity layer.shadowOffset = offSet layer.shadowRadius = radius layer.shadowPath = UIBezierPath(rect: self.bounds).cgPath layer.shouldRasterize = true layer.rasterizationScale = scale ? UIScreen.main.scale : 1 } } internal extension UIColor { var isDarkColor: Bool { var r, g, b, a: CGFloat (r, g, b, a) = (0, 0, 0, 0) self.getRed(&r, green: &g, blue: &b, alpha: &a) let lum = 0.2126 * r + 0.7152 * g + 0.0722 * b return lum < 0.50 ? true : false } }
I noticed this: UIImage(systemName: "globe")! Is there a reason why you instantiate a custom image this way? Is "globe" an apple provided default image? You should be really using, if this isn't a default image. UIImage(named:"globe")!
Dont use Force unwrapping when you do not have confirmation about data always use optional binding and do change following line in code from this UIImage(systemName: "globe")! to UIImage(named:"globe")! .
Swift make UIView border into Gradient Color
I want to create a gradient border on a UIView. The following code can produce a solid for the view Box1. nothing I have found allows me to change the frameColor to a gradient. var frameColor = UIColor.red.cgColor var leftBorder = CALayer() leftBorder.frame = CGRect(x: 0.0, y: 0, width: 1, height: box1.frame.size.height ) leftBorder.backgroundColor = frameColor I am using Swift 5 and Xcode 11. Thank you.
Try with below extension public extension UIView { private static let kLayerNameGradientBorder = "GradientBorderLayer" func setGradientBorder( width: CGFloat, colors: [UIColor], startPoint: CGPoint = CGPoint(x: 0.5, y: 0), endPoint: CGPoint = CGPoint(x: 0.5, y: 1) ) { let existedBorder = gradientBorderLayer() let border = existedBorder ?? CAGradientLayer() border.frame = bounds border.colors = colors.map { return $0.cgColor } border.startPoint = startPoint border.endPoint = endPoint let mask = CAShapeLayer() mask.path = UIBezierPath(roundedRect: bounds, cornerRadius: 0).cgPath mask.fillColor = UIColor.clear.cgColor mask.strokeColor = UIColor.white.cgColor mask.lineWidth = width border.mask = mask let exists = existedBorder != nil if !exists { layer.addSublayer(border) } } func removeGradientBorder() { self.gradientBorderLayer()?.removeFromSuperlayer() } private func gradientBorderLayer() -> CAGradientLayer? { let borderLayers = layer.sublayers?.filter { return $0.name == UIView.kLayerNameGradientBorder } if borderLayers?.count ?? 0 > 1 { fatalError() } return borderLayers?.first as? CAGradientLayer } } Usage self.borderView.setGradientBorder(width: 5.0, colors: [UIColor.red , UIColor.blue]) I hope this will reach your requirement. https://medium.com/#kushal0409/gradient-button-3dc8ef763039
There is no off-the-shelf way to do this, but you could build it yourself. Off the top of my head, the approach might look like this: Create a CAGradientLayer and set it up to draw your gradient as desired. Create a CAShapeLayer that contains an empty rectangle that is your frame. Add your shape layer as the mask of your gradient layer. Add the gradient layer to your view as a sub-layer of the view's content layer.
Swift 5 extension (works with corner radius) extension UIView { func gradientBorder(colors: [UIColor], isVertical: Bool){ self.layer.masksToBounds = true //Create gradient layer let gradient = CAGradientLayer() gradient.frame = CGRect(origin: CGPoint.zero, size: self.bounds.size) gradient.colors = colors.map({ (color) -> CGColor in color.cgColor }) //Set gradient direction if(isVertical){ gradient.startPoint = CGPoint(x: 0.5, y: 0) gradient.endPoint = CGPoint(x: 0.5, y: 1) } else { gradient.startPoint = CGPoint(x: 0, y: 0.5) gradient.endPoint = CGPoint(x: 1, y: 0.5) } //Create shape layer let shape = CAShapeLayer() shape.lineWidth = 1 shape.path = UIBezierPath(roundedRect: gradient.frame.insetBy(dx: 1, dy: 1), cornerRadius: self.layer.cornerRadius).cgPath shape.strokeColor = UIColor.black.cgColor shape.fillColor = UIColor.clear.cgColor gradient.mask = shape //Add layer to view self.layer.addSublayer(gradient) gradient.zPosition = 0 } }
Custom Segmented Control Effect
There is what I want to do : However, with Segmented Control : The only I can do is to choose background and tintColor. How can I personalize Segmented Control to achieve this goal? If not possible, How could I do ? Many Thanks!
Try this in Swift 3: mySegment.isMomentary = true mySegment.layer.cornerRadius = mySegment.bounds.height / 2 mySegment.layer.borderColor = UIColor.black.cgColor mySegment.layer.borderWidth = 1 mySegment.tintColor = UIColor.black mySegment.clipsToBounds = true Or you must to use UIBezierPath and CAShapeLayer var OldShape = CAShapeLayer() var OldShape2 = CAShapeLayer() override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) mySegment.isMomentary = true mySegment.tintColor = UIColor.red mySegment.setTitle("Oui", forSegmentAt: 0) mySegment.setTitle("Non", forSegmentAt: 1) drawBorderLine(myView: mySegment) mySegment.layer.cornerRadius = mySegment.bounds.height / 2 mySegment.clipsToBounds = true } func drawBorderLine(myView : UISegmentedControl) { let path = UIBezierPath(roundedRect: myView.bounds, byRoundingCorners: [.topLeft, .bottomLeft, .bottomRight, .topRight], cornerRadii: CGSize(width: 20.0, height: myView.bounds.height / 2)) path.move(to: CGPoint(x: myView.bounds.midX, y: myView.bounds.minY)) path.addLine(to: CGPoint(x: myView.bounds.midX, y: myView.bounds.maxY)) let shape = CAShapeLayer() shape.path = path.cgPath shape.fillColor = UIColor.clear.cgColor shape.lineWidth = 3 shape.lineCap = kCALineCapRound shape.strokeColor = UIColor.lightGray.cgColor myView.layer.insertSublayer(shape, at: 0) } #IBAction func valueChange(_ sender: UISegmentedControl) { // setting shape red let shape = CAShapeLayer() shape.fillColor = UIColor.clear.cgColor shape.lineWidth = 3 shape.lineCap = kCALineCapRound shape.strokeColor = UIColor.red.cgColor // setting shape lightGray let shape2 = CAShapeLayer() shape2.fillColor = UIColor.clear.cgColor shape2.lineWidth = 3 shape2.lineCap = kCALineCapRound shape2.strokeColor = UIColor.lightGray.cgColor switch sender.selectedSegmentIndex { case 1: let element = sender.subviews[0] let path = UIBezierPath(roundedRect: element.bounds, byRoundingCorners: [.topRight, .bottomRight], cornerRadii: CGSize(width: 20.0, height: element.bounds.height / 2)) shape.path = path.cgPath let element2 = sender.subviews[1] let path2 = UIBezierPath(roundedRect: element2.bounds, byRoundingCorners: [.bottomLeft, .topLeft], cornerRadii: CGSize(width: 20.0, height: element2.bounds.height / 2)) shape2.path = path2.cgPath SelectAndDeselect(myViewSelect: element, myViewDeselect: element2, select: shape, deselect: shape2) case 0: let element = sender.subviews[1] let path = UIBezierPath(roundedRect: element.bounds, byRoundingCorners: [.topLeft, .bottomLeft], cornerRadii: CGSize(width: 20.0, height: element.bounds.height / 2)) shape.path = path.cgPath let element2 = sender.subviews[0] let path2 = UIBezierPath(roundedRect: element2.bounds, byRoundingCorners: [.bottomRight, .topRight], cornerRadii: CGSize(width: 20.0, height: element2.bounds.height / 2)) shape2.path = path2.cgPath SelectAndDeselect(myViewSelect: element, myViewDeselect: element2, select: shape, deselect: shape2) default: break } } func SelectAndDeselect(myViewSelect : UIView, myViewDeselect : UIView, select : CAShapeLayer, deselect : CAShapeLayer ) { if OldShape.path != nil { OldShape.removeFromSuperlayer() OldShape = select myViewSelect.layer.addSublayer(OldShape) }else{ OldShape = select myViewSelect.layer.addSublayer(OldShape) } if OldShape2.path != nil{ OldShape2.removeFromSuperlayer() OldShape2 = deselect myViewDeselect.layer.addSublayer(OldShape2) }else{ OldShape2 = deselect myViewDeselect.layer.addSublayer(OldShape2) } }
Swift - UIView with shadow different corner radiuses [duplicate]
Is there a way to set cornerRadius for only top-left and top-right corner of a UIView? I tried the following, but it end up not seeing the view anymore. UIView *view = [[UIView alloc] initWithFrame:frame]; CALayer *layer = [CALayer layer]; UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRoundedRect:frame byRoundingCorners:(UIRectCornerTopLeft|UIRectCornerTopRight) cornerRadii:CGSizeMake(3.0, 3.0)]; layer.shadowPath = shadowPath.CGPath; view.layer.mask = layer;
I am not sure why your solution did not work but the following code is working for me. Create a bezier mask and apply it to your view. In my code below I was rounding the bottom corners of the _backgroundView with a radius of 3 pixels. self is a custom UITableViewCell: UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:self.backgroundImageView.bounds byRoundingCorners:(UIRectCornerBottomLeft | UIRectCornerBottomRight) cornerRadii:CGSizeMake(20, 20) ]; CAShapeLayer *maskLayer = [CAShapeLayer layer]; maskLayer.frame = self.bounds; maskLayer.path = maskPath.CGPath; self.backgroundImageView.layer.mask = maskLayer; Swift 2.0 version with some improvements: let path = UIBezierPath(roundedRect:viewToRound.bounds, byRoundingCorners:[.TopRight, .BottomLeft], cornerRadii: CGSizeMake(20, 20)) let maskLayer = CAShapeLayer() maskLayer.path = path.CGPath viewToRound.layer.mask = maskLayer Swift 3.0 version: let path = UIBezierPath(roundedRect:viewToRound.bounds, byRoundingCorners:[.topRight, .bottomLeft], cornerRadii: CGSize(width: 20, height: 20)) let maskLayer = CAShapeLayer() maskLayer.path = path.cgPath viewToRound.layer.mask = maskLayer Swift extension here
And finally… there is CACornerMask in iOS11! With CACornerMask it can be done pretty easy: let view = UIView() view.clipsToBounds = true view.layer.cornerRadius = 10 view.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner] // Top right corner, Top left corner respectively
Pay attention to the fact that if you have layout constraints attached to it, you must refresh this as follows in your UIView subclass: override func layoutSubviews() { super.layoutSubviews() roundCorners(corners: [.topLeft, .topRight], radius: 3.0) } If you don't do that it won't show up. And to round corners, use the extension: extension UIView { func roundCorners(corners: UIRectCorner, radius: CGFloat) { let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius)) let mask = CAShapeLayer() mask.path = path.cgPath layer.mask = mask } } Additional view controller case: Whether you can't or wouldn't want to subclass a view, you can still round a view. Do it from its view controller by overriding the viewWillLayoutSubviews() function, as follows: class MyVC: UIViewController { /// The view to round the top-left and top-right hand corners let theView: UIView = { let v = UIView(frame: CGRect(x: 10, y: 10, width: 200, height: 200)) v.backgroundColor = .red return v }() override func loadView() { super.loadView() view.addSubview(theView) } override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() // Call the roundCorners() func right there. theView.roundCorners(corners: [.topLeft, .topRight], radius: 30) } }
Here is a Swift version of #JohnnyRockex answer 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 } } view.roundCorners([.topLeft, .bottomRight], radius: 10) Note If you're using Auto Layout, you'll need to subclass your UIView and call roundCorners in the view's layoutSubviews for optimal effect. class View: UIView { override func layoutSubviews() { super.layoutSubviews() self.roundCorners([.topLeft, .bottomLeft], radius: 10) } }
Swift code example here: https://stackoverflow.com/a/35621736/308315 Not directly. You will have to: Create a CAShapeLayer Set its path to be a CGPathRef based on view.bounds but with only two rounded corners (probably by using +[UIBezierPath bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:]) Set your view.layer.mask to be the CAShapeLayer
Here is a short method implemented like this: - (void)viewDidLoad { [super viewDidLoad]; UIButton *openInMaps = [UIButton new]; [openInMaps setFrame:CGRectMake(15, 135, 114, 70)]; openInMaps = (UIButton *)[self roundCornersOnView:openInMaps onTopLeft:NO topRight:NO bottomLeft:YES bottomRight:NO radius:5.0]; } - (UIView *)roundCornersOnView:(UIView *)view onTopLeft:(BOOL)tl topRight:(BOOL)tr bottomLeft:(BOOL)bl bottomRight:(BOOL)br radius:(float)radius { if (tl || tr || bl || br) { UIRectCorner corner = 0; if (tl) {corner = corner | UIRectCornerTopLeft;} if (tr) {corner = corner | UIRectCornerTopRight;} if (bl) {corner = corner | UIRectCornerBottomLeft;} if (br) {corner = corner | UIRectCornerBottomRight;} UIView *roundedView = view; UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:roundedView.bounds byRoundingCorners:corner cornerRadii:CGSizeMake(radius, radius)]; CAShapeLayer *maskLayer = [CAShapeLayer layer]; maskLayer.frame = roundedView.bounds; maskLayer.path = maskPath.CGPath; roundedView.layer.mask = maskLayer; return roundedView; } return view; }
In Swift 4.1 and Xcode 9.4.1 In iOS 11 this single line is enough: detailsSubView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]//Set your view here See the complete code: //In viewDidLoad if #available(iOS 11.0, *) { detailsSubView.clipsToBounds = false detailsSubView.layer.cornerRadius = 10 detailsSubView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner] } else { //For lower versions } But for lower versions let rectShape = CAShapeLayer() rectShape.bounds = detailsSubView.frame rectShape.position = detailsSubView.center rectShape.path = UIBezierPath(roundedRect: detailsSubView.bounds, byRoundingCorners: [.topLeft , .topRight], cornerRadii: CGSize(width: 20, height: 20)).cgPath detailsSubView.layer.mask = rectShape Complete code is. if #available(iOS 11.0, *) { detailsSubView.clipsToBounds = false detailsSubView.layer.cornerRadius = 10 detailsSubView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner] } else { let rectShape = CAShapeLayer() rectShape.bounds = detailsSubView.frame rectShape.position = detailsSubView.center rectShape.path = UIBezierPath(roundedRect: detailsSubView.bounds, byRoundingCorners: [.topLeft , .topRight], cornerRadii: CGSize(width: 20, height: 20)).cgPath detailsSubView.layer.mask = rectShape } If you are using AutoResizing in storyboard write this code in viewDidLayoutSubviews(). override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() if #available(iOS 11.0, *) { detailsSubView.clipsToBounds = false detailsSubView.layer.cornerRadius = 10 detailsSubView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner] } else { let rectShape = CAShapeLayer() rectShape.bounds = detailsSubView.frame rectShape.position = detailsSubView.center rectShape.path = UIBezierPath(roundedRect: detailsSubView.bounds, byRoundingCorners: [.topLeft , .topRight], cornerRadii: CGSize(width: 20, height: 20)).cgPath detailsSubView.layer.mask = rectShape } }
There is a super simple way of doing it. I found it on here. view.clipsToBounds = true view.layer.cornerRadius = 24 view.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner] It uses the stock cornerRadius property on the CALayer of a view. You just need to define the corners. layerMinXMinYCorner is top left layerMaxXMinYCorner is top right.
This would be the simplest answer: yourView.layer.cornerRadius = 8 yourView.layer.masksToBounds = true yourView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
Swift 4 Swift 5 easy way in 1 line Usage: //MARK:- Corner Radius of only two side of UIViews self.roundCorners(view: yourview, corners: [.bottomLeft, .topRight], radius: 12.0) Function: //MARK:- Corner Radius of only two side of UIViews func roundCorners(view :UIView, corners: UIRectCorner, radius: CGFloat){ let path = UIBezierPath(roundedRect: view.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius)) let mask = CAShapeLayer() mask.path = path.cgPath view.layer.mask = mask } In Objective-C Usage: [self.verticalSeparatorView roundCorners:UIRectCornerTopLeft | UIRectCornerTopRight radius:10.0]; Function used in a Category (only one corner): -(void)roundCorners: (UIRectCorner) corners radius:(CGFloat)radius { UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:corners cornerRadii:CGSizeMake(radius, radius)]; CAShapeLayer *mask = [[CAShapeLayer alloc] init]; mask.path = path.CGPath; self.layer.mask = mask; }
iOS 11 , Swift 4 And you can try this code: if #available(iOS 11.0, *) { element.clipsToBounds = true element.layer.cornerRadius = CORNER_RADIUS element.layer.maskedCorners = [.layerMaxXMaxYCorner] } else { // Fallback on earlier versions } And you can using this in table view cell.
My solution for rounding specific corners of UIView and UITextFiels in swift is to use .layer.cornerRadius and layer.maskedCorners of actual UIView or UITextFields. Example: fileprivate func inputTextFieldStyle() { inputTextField.layer.masksToBounds = true inputTextField.layer.borderWidth = 1 inputTextField.layer.cornerRadius = 25 inputTextField.layer.maskedCorners = [.layerMaxXMaxYCorner,.layerMaxXMinYCorner] inputTextField.layer.borderColor = UIColor.white.cgColor } And by using .layerMaxXMaxYCorner and .layerMaxXMinYCorner , I can specify top right and bottom right corner of the UITextField to be rounded. You can see the result here:
Try this code, UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:view.bounds byRoundingCorners:( UIRectCornerTopLeft | UIRectCornerTopRight) cornerRadii:CGSizeMake(5.0, 5.0)]; CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init]; maskLayer.frame = self.view.bounds; maskLayer.path = maskPath.CGPath; view.layer.mask = maskLayer;
Emma: .TopRight and .BottomRight are not working for you perhaps because the call to view.roundCorners is done BEFORE final view bounds are calculated. Note that the Bezier Path derives from the view bounds at the time it is called. For example, if auto layout will narrow the view, the round corners on the right side might be outside the view. Try to call it in viewDidLayoutSubviews, where the view's bound is final.
Swift 4 extension UIView { func roundTop(radius:CGFloat = 5){ self.clipsToBounds = true self.layer.cornerRadius = radius if #available(iOS 11.0, *) { self.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner] } else { // Fallback on earlier versions } } func roundBottom(radius:CGFloat = 5){ self.clipsToBounds = true self.layer.cornerRadius = radius if #available(iOS 11.0, *) { self.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner] } else { // Fallback on earlier versions } } }
Simple extension extension UIView { func roundCorners(corners: UIRectCorner, radius: CGFloat) { if #available(iOS 11, *) { self.clipsToBounds = true self.layer.cornerRadius = radius var masked = CACornerMask() if corners.contains(.topLeft) { masked.insert(.layerMinXMinYCorner) } if corners.contains(.topRight) { masked.insert(.layerMaxXMinYCorner) } if corners.contains(.bottomLeft) { masked.insert(.layerMinXMaxYCorner) } if corners.contains(.bottomRight) { masked.insert(.layerMaxXMaxYCorner) } self.layer.maskedCorners = masked } else { let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius)) let mask = CAShapeLayer() mask.path = path.cgPath layer.mask = mask } } } Usage: view.roundCorners(corners: [.bottomLeft, .bottomRight], radius: 12)
Use this extension, it'll cover everything. extension UIView { func roundTopCorners(radius: CGFloat = 10) { self.clipsToBounds = true self.layer.cornerRadius = radius if #available(iOS 11.0, *) { self.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner] } else { self.roundCorners(corners: [.topLeft, .topRight], radius: radius) } } func roundBottomCorners(radius: CGFloat = 10) { self.clipsToBounds = true self.layer.cornerRadius = radius if #available(iOS 11.0, *) { self.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner] } else { self.roundCorners(corners: [.bottomLeft, .bottomRight], radius: radius) } } private func roundCorners(corners: UIRectCorner, radius: CGFloat) { let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius)) let mask = CAShapeLayer() mask.path = path.cgPath layer.mask = mask } } and then use it like this:- override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) self.yourView.roundTopCorners() } Note:- I'll recommend you to don't put this code inside viewDidLayoutSubviews(), because whenever view updates, you'll get call inside it. So use viewDidAppear(), it'll work like a charm.
Here is best way Swift 5: import UIKit extension UIView { func roundCorners(radius: CGFloat = 10, corners: UIRectCorner = .allCorners) { self.clipsToBounds = true self.layer.cornerRadius = radius if #available(iOS 11.0, *) { var arr: CACornerMask = [] let allCorners: [UIRectCorner] = [.topLeft, .topRight, .bottomLeft, .bottomRight, .allCorners] for corn in allCorners { if(corners.contains(corn)){ switch corn { case .topLeft: arr.insert(.layerMinXMinYCorner) case .topRight: arr.insert(.layerMaxXMinYCorner) case .bottomLeft: arr.insert(.layerMinXMaxYCorner) case .bottomRight: arr.insert(.layerMaxXMaxYCorner) case .allCorners: arr.insert(.layerMinXMinYCorner) arr.insert(.layerMaxXMinYCorner) arr.insert(.layerMinXMaxYCorner) arr.insert(.layerMaxXMaxYCorner) default: break } } } self.layer.maskedCorners = arr } else { self.roundCornersBezierPath(corners: corners, radius: radius) } } private func roundCornersBezierPath(corners: UIRectCorner, radius: CGFloat) { let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius)) let mask = CAShapeLayer() mask.path = path.cgPath layer.mask = mask } }
A way to do this programmatically would be to create a UIView over the top part of the UIView that has the rounded corners. Or you could hide the top underneath something.
// Create the path (with only the top-left corner rounded) UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:view.bounds byRoundingCorners:(UIRectCornerBottomLeft | UIRectCornerBottomRight) cornerRadii:CGSizeMake(7.0, 7.0)]; // Create the shape layer and set its path CAShapeLayer *maskLayer = [CAShapeLayer layer]; maskLayer.frame = cell.stripBlackImnageView.bounds; maskLayer.path = maskPath.CGPath; // Set the newly created shapelayer as the mask for the image view's layer view.layer.mask = maskLayer;
The easiest way would be to make a mask with a rounded corner layer. CALayer *maskLayer = [CALayer layer]; maskLayer.frame = CGRectMake(0,0,maskWidth ,maskHeight); maskLayer.contents = (__bridge id)[[UIImage imageNamed:#"maskImageWithRoundedCorners.png"] CGImage]; aUIView.layer.mask = maskLayer; And don't forget to: #import <QuartzCore/QuartzCore.h>
All of the answers already given are really good and valid (especially Yunus idea of using the mask property). However I needed something a little more complex because my layer could often change sizes which mean I needed to call that masking logic every time and this was a little bit annoying. I used swift extensions and computed properties to build a real cornerRadii property which takes care of auto updating the mask when layer is layed out. This was achieved using Peter Steinberg great Aspects library for swizzling. Full code is here: extension CALayer { // This will hold the keys for the runtime property associations private struct AssociationKey { static var CornerRect:Int8 = 1 // for the UIRectCorner argument static var CornerRadius:Int8 = 2 // for the radius argument } // new computed property on CALayer // You send the corners you want to round (ex. [.TopLeft, .BottomLeft]) // and the radius at which you want the corners to be round var cornerRadii:(corners: UIRectCorner, radius:CGFloat) { get { let number = objc_getAssociatedObject(self, &AssociationKey.CornerRect) as? NSNumber ?? 0 let radius = objc_getAssociatedObject(self, &AssociationKey.CornerRadius) as? NSNumber ?? 0 return (corners: UIRectCorner(rawValue: number.unsignedLongValue), radius: CGFloat(radius.floatValue)) } set (v) { let radius = v.radius let closure:((Void)->Void) = { let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: v.corners, cornerRadii: CGSize(width: radius, height: radius)) let mask = CAShapeLayer() mask.path = path.CGPath self.mask = mask } let block: #convention(block) Void -> Void = closure let objectBlock = unsafeBitCast(block, AnyObject.self) objc_setAssociatedObject(self, &AssociationKey.CornerRect, NSNumber(unsignedLong: v.corners.rawValue), .OBJC_ASSOCIATION_RETAIN) objc_setAssociatedObject(self, &AssociationKey.CornerRadius, NSNumber(float: Float(v.radius)), .OBJC_ASSOCIATION_RETAIN) do { try aspect_hookSelector("layoutSublayers", withOptions: .PositionAfter, usingBlock: objectBlock) } catch _ { } } } } I wrote a simple blog post explaining this.
A lovely extension to reuse Yunus Nedim Mehel solution Swift 2.3 extension UIView { func roundCornersWithLayerMask(cornerRadii: CGFloat, corners: UIRectCorner) { let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: cornerRadii, height: cornerRadii)) let maskLayer = CAShapeLayer() maskLayer.path = path.CGPath layer.mask = maskLayer } } Usage let view = UIView() view.roundCornersWithLayerMask(10,[.TopLeft,.TopRight])
If you're looking for an interface builder only solution there is one for iOS 11 and higher. See my answer here: https://stackoverflow.com/a/58626264
This is how you can set a corner radius for each corner of a button with Xamarin in C#: var maskPath = UIBezierPath.FromRoundedRect(MyButton.Bounds, UIRectCorner.BottomLeft | UIRectCorner.BottomRight, new CGSize(10.0, 10.0)); var maskLayer = new CAShapeLayer { Frame = MyButton.Bounds, Path = maskPath.CGPath }; MyButton.Layer.Mask = maskLayer;
For SwiftUI I found these solutions you can check from here https://stackoverflow.com/a/56763282/3716103 I highly recommend the first one Option 1: Using Path + GeometryReader (more info on GeometryReader: https://swiftui-lab.com/geometryreader-to-the-rescue/) struct ContentView : View { var body: some View { Text("Hello World!") .foregroundColor(.white) .font(.largeTitle) .padding(20) .background(RoundedCorners(color: .blue, tl: 0, tr: 30, bl: 30, br: 0)) } } RoundedCorners struct RoundedCorners: View { var color: Color = .white var tl: CGFloat = 0.0 var tr: CGFloat = 0.0 var bl: CGFloat = 0.0 var br: CGFloat = 0.0 var body: some View { GeometryReader { geometry in Path { path in let w = geometry.size.width let h = geometry.size.height // Make sure we do not exceed the size of the rectangle let tr = min(min(self.tr, h/2), w/2) let tl = min(min(self.tl, h/2), w/2) let bl = min(min(self.bl, h/2), w/2) let br = min(min(self.br, h/2), w/2) path.move(to: CGPoint(x: w / 2.0, y: 0)) path.addLine(to: CGPoint(x: w - tr, y: 0)) path.addArc(center: CGPoint(x: w - tr, y: tr), radius: tr, startAngle: Angle(degrees: -90), endAngle: Angle(degrees: 0), clockwise: false) path.addLine(to: CGPoint(x: w, y: h - be)) path.addArc(center: CGPoint(x: w - br, y: h - br), radius: br, startAngle: Angle(degrees: 0), endAngle: Angle(degrees: 90), clockwise: false) path.addLine(to: CGPoint(x: bl, y: h)) path.addArc(center: CGPoint(x: bl, y: h - bl), radius: bl, startAngle: Angle(degrees: 90), endAngle: Angle(degrees: 180), clockwise: false) path.addLine(to: CGPoint(x: 0, y: tl)) path.addArc(center: CGPoint(x: tl, y: tl), radius: tl, startAngle: Angle(degrees: 180), endAngle: Angle(degrees: 270), clockwise: false) } .fill(self.color) } } } RoundedCorners_Previews struct RoundedCorners_Previews: PreviewProvider { static var previews: some View { RoundedCorners(color: .pink, tl: 40, tr: 40, bl: 40, br: 40) } }
Use this extension for set corner round and round border with round corners use like this : override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() myView.roundCornersWithBorder(corners: [.topLeft, .topRight], radius: 8.0) myView.roundCorners(corners: [.topLeft, .topRight], radius: 8.0) } extension UIView { func roundCorners(corners: UIRectCorner, radius: CGFloat) { let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius)) let mask = CAShapeLayer() mask.path = path.cgPath layer.mask = mask } func roundCornersWithBorder(corners: UIRectCorner, radius: CGFloat) { let maskLayer = CAShapeLayer() maskLayer.frame = bounds maskLayer.path = UIBezierPath(roundedRect: bounds, byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width: radius, height: radius)).cgPath layer.mask = maskLayer // Add border let borderLayer = CAShapeLayer() borderLayer.path = maskLayer.path // Reuse the Bezier path borderLayer.fillColor = UIColor.clear.cgColor borderLayer.strokeColor = UIColor(red:3/255, green:33/255, blue:70/255, alpha: 0.15).cgColor borderLayer.lineWidth = 2 borderLayer.frame = bounds layer.addSublayer(borderLayer) } }
After change bit of code #apinho In swift 4.3 working fine extension UIView { func roundCornersWithLayerMask(cornerRadii: CGFloat, corners: UIRectCorner) { let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: cornerRadii, height: cornerRadii)) let maskLayer = CAShapeLayer() maskLayer.path = path.cgPath layer.mask = maskLayer } } To use this function for you view YourViewName. roundCornersWithLayerMask(cornerRadii: 20,corners: [.topLeft,.topRight])
Another version of Stephane's answer. import UIKit class RoundCornerView: UIView { var corners : UIRectCorner = [.topLeft,.topRight,.bottomLeft,.bottomRight] var roundCornerRadius : CGFloat = 0.0 override func layoutSubviews() { super.layoutSubviews() if corners.rawValue > 0 && roundCornerRadius > 0.0 { self.roundCorners(corners: corners, radius: roundCornerRadius) } } private func roundCorners(corners: UIRectCorner, radius: CGFloat) { let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius)) let mask = CAShapeLayer() mask.path = path.cgPath layer.mask = mask } }
In Swift 4.2, Create it via #IBDesignable like this: #IBDesignable class DesignableViewCustomCorner: UIView { #IBInspectable var cornerRadious: CGFloat = 0 { didSet { let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width: cornerRadious, height: cornerRadious)) let mask = CAShapeLayer() mask.path = path.cgPath self.layer.mask = mask } } }