37

Is there a way to set cornerRadius for only bottom-left, bottom-right and top-left corner of a UIView?

I tried the following, but it ended up making the view disappear. Is there anything wrong with the code below?

    UIBezierPath *maskPath;
    maskPath = [UIBezierPath bezierPathWithRoundedRect:view.bounds byRoundingCorners:(UIRectCornerBottomLeft | UIRectCornerBottomRight) cornerRadii:CGSizeMake(20.0, 20.0)];
    CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
    maskLayer.path = maskPath.CGPath;
    view.layer.mask = maskLayer;
Siva
  • 1,848
  • 2
  • 23
  • 40
  • Try to use `UIBezierPath* maskPath = [UIBezierPath new];` and then use `addLineToPoint:`, `addArcWithCenter:radius:startAngle:endAngle:clockwise:` methods. – Valentin Shamardin Sep 02 '14 at 05:42
  • Your code seems all right. Just check that you have added QuartzCore framework and imported in the class where you are writing this code. I don't know that exactly is the case but happened with me earlier. – Aditya Mathur Sep 02 '14 at 06:22
  • possible duplicate of [Rounded UIView using CALayers - only some corners - How?](http://stackoverflow.com/questions/2264083/rounded-uiview-using-calayers-only-some-corners-how) – Stuart Sep 02 '14 at 06:34

11 Answers11

141

You can do it like this:

UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:self.viewOutlet.bounds byRoundingCorners:(UIRectCornerTopLeft | UIRectCornerBottomLeft | UIRectCornerBottomRight) cornerRadii:CGSizeMake(10.0, 10.0)];

CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = self.view.bounds;
maskLayer.path  = maskPath.CGPath;
self.viewOutlet.layer.mask = maskLayer;

enter image description here

Update:
If You need border just create another CAShapeLayer and add it to view's layer as sublayer. Like this (place this code below upper code):

CAShapeLayer *borderLayer = [[CAShapeLayer alloc] init];
borderLayer.frame = self.view.bounds;
borderLayer.path  = maskPath.CGPath;
borderLayer.lineWidth   = 4.0f;
borderLayer.strokeColor = [UIColor blackColor].CGColor;
borderLayer.fillColor   = [UIColor clearColor].CGColor;

[self.viewOutlet.layer addSublayer:borderLayer];

enter image description here

In swift 3.0 like this:

let maskPath = UIBezierPath.init(roundedRect: self.viewOutlet.bounds, byRoundingCorners:[.topLeft, .bottomLeft], cornerRadii: CGSize.init(width: 10.0, height: 10.0))
let maskLayer = CAShapeLayer()
maskLayer.frame = self.viewOutlet.bounds
maskLayer.path = maskPath.cgPath
self.viewOutlet.layer.mask = maskLayer
Subhash Khimani
  • 427
  • 7
  • 22
Justin Boo
  • 10,132
  • 8
  • 50
  • 71
  • here i need to set border for this view... Is it possible to show border? – Siva Sep 02 '14 at 09:30
  • `borderLayer.frame = self.view.bounds` means no binding to the view frame. Will it look ugly if animated? – Léon Pelletier Oct 21 '15 at 04:42
  • It is not pretty right working, for example you have gray background and white UIView. You want to make shape with rounded corners that will be white and with dark gray stroke. And Here is the problem if the stroke is smaller than 4 than you can see the white corners of your view that are under your rounded corner shape and because of gray background they are pretty good seen. – Roman Safin Dec 22 '15 at 16:57
  • You might be using storyboard with autoresizing constraints. try this.translatesAutoresizingMaskIntoConstraints = YES; – vaibby May 04 '16 at 10:43
  • I used round all corners but only the top and bottom left are rounded. what gives? – PLOW Sep 12 '16 at 19:34
  • @JustinBoo Thanks a lot for this. Used a similar implementation as a UIView extension to easily set individual corner radii of views. Solved a problem I've been stuck on within 2 minutes of finding your answer. – Jake T. Nov 17 '16 at 17:52
  • @User_1191 because it doesn't have `UIRectCornerTopRight`. – Justin Boo Dec 27 '16 at 07:19
  • @JustinBoo `UIRectCornerBottomRight` – User_1191 Dec 27 '16 at 08:22
  • @JustinBoo please give answer in swift 3 too. – Mamta Jan 27 '17 at 11:51
  • @JustinBoo how do we add shadow to it ? – omarojo Oct 16 '20 at 12:37
18

Tested in xcode 8 and 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
    }
}

And use like this

YourView.roundCorners([.topLeft, .bottomLeft], radius: 10)
Museer Ahamad Ansari
  • 5,414
  • 3
  • 39
  • 45
8

Use a custom UIView and Implement the below code

#import "CustomUIView.h"

@implementation CustomView

- (void)drawRect:(CGRect)rect
{
    // Drawing code
    CAShapeLayer * maskLayer = [CAShapeLayer layer];
    maskLayer.path = [UIBezierPath bezierPathWithRoundedRect: self.bounds byRoundingCorners: UIRectCornerTopLeft | UIRectCornerBottomLeft | UIRectCornerBottomRight cornerRadii: (CGSize){20.0, 20.0}].CGPath;

    self.layer.mask = maskLayer;
}

@end

Output:

enter image description here

Look at the UIBezierPath.h options :

typedef NS_OPTIONS(NSUInteger, UIRectCorner) {
    UIRectCornerTopLeft     = 1 << 0,
    UIRectCornerTopRight    = 1 << 1,
    UIRectCornerBottomLeft  = 1 << 2,
    UIRectCornerBottomRight = 1 << 3,
    UIRectCornerAllCorners  = ~0UL
};
Shamsudheen TK
  • 30,739
  • 9
  • 69
  • 102
6

Setting corner-radius for a view in Swift

The creation and masking of layers should run inside the optional drawRect() block inherited from UIView

    override func drawRect(rect: CGRect) {
        super.drawRect(rect)

        let maskPath = UIBezierPath(roundedRect: self.view.bounds, byRoundingCorners: [.TopLeft, .BottomLeft, .BottomRight], cornerRadii: CGSizeMake(10, 10))
        let maskLayer = CAShapeLayer()
        maskLayer.frame = self.view.bounds
        maskLayer.path  = maskPath.CGPath
        self.view.layer.mask = maskLayer
    }
metpb
  • 513
  • 8
  • 20
4

I know it's very late, but i just create one method where you can pass only one or multiple UIRectCorners.

  [self setMaskTo:myView byRoundingCorners:(UIRectCornerTopLeft|UIRectCornerTopRight)];

- (void)setMaskTo:(UIView*)view byRoundingCorners:(UIRectCorner)corners
        {
            UIBezierPath *rounded = [UIBezierPath bezierPathWithRoundedRect:view.bounds
                                                          byRoundingCorners:corners
                                                                cornerRadii:CGSizeMake(8.0, 8.0)];
            CAShapeLayer *shape = [[CAShapeLayer alloc] init];
            [shape setPath:rounded.CGPath];
            view.layer.mask = shape;
    }
Siddhesh Mahadeshwar
  • 1,591
  • 14
  • 16
3

hope this will help you

your above code running perfectly on my machine , may be you set CAShapeLayer frame equal to your view frame due to which your view will disappear but i am not seeing this line in your code ,so please check your view property and apply below code

  UIBezierPath *maskPath;
    maskPath = [UIBezierPath bezierPathWithRoundedRect:viewName.bounds
                                     byRoundingCorners:(UIRectCornerBottomLeft | UIRectCornerBottomRight |UIRectCornerTopLeft)
                                           cornerRadii:CGSizeMake(20.0, 20.0)];
    CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
    maskLayer.frame =viewName.bounds; 
    maskLayer.path = maskPath.CGPath;
   viewName.layer.mask = maskLayer;
Anurag Bhakuni
  • 2,379
  • 26
  • 32
2

On iOS 11, What you only need is the maskedCorners.

    let cornerRadius: CGFloat = 6.0
    if #available(iOS 11, *) {
        productImageView.layer.cornerRadius  = cornerRadius
        productImageView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]

    } else {
        let path        = UIBezierPath(roundedRect: bounds, byRoundingCorners: [.topLeft , .topRight], cornerRadii:CGSize(width: cornerRadius, height: cornerRadius))
        let maskLayer   = CAShapeLayer()
        maskLayer.frame = bounds
        maskLayer.path  = path.cgPath
        productImageView.mask                = maskLayer
        productImageView.layer.masksToBounds = true
    }
Den
  • 3,179
  • 29
  • 26
0
UIBezierPath *maskPath;
maskPath = [UIBezierPath bezierPathWithRoundedRect:someView.bounds 
                             byRoundingCorners:(UIRectCornerTopLeft|UIRectCornerTopRight|UIRectCornerBottomLeft|UIRectCornerBottomRight) 
                                   cornerRadii:CGSizeMake(10.0,10.0,5.0, 10.0)];


CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = self.bounds;
maskLayer.path = maskPath.CGPath;
someView.layer.mask = maskLayer;
Vijay Rathod
  • 197
  • 1
  • 3
  • 11
0

Try this code

-(void)setMaskTo:(UIView*)view byRoundingCorners:(UIRectCorner)corners {
    UIBezierPath* rounded = [UIBezierPath bezierPathWithRoundedRect:view.bounds byRoundingCorners:corners cornerRadii:CGSizeMake(10.0, 10.0)];
    CAShapeLayer* shape = [[CAShapeLayer alloc] init];
    [shape setPath:rounded.CGPath];
    view.layer.mask = shape;
}

call using

[self setMaskTo:myView byRoundingCorners:UIRectCornerTopLeft|UIRectCornerTopRight];

Available options:

UIRectCornerTopLeft, UIRectCornerTopRight,UIRectCornerBottomLeft,UIRectCornerBottomRight,UIRectCornerAllCorners
Hardik Thakkar
  • 15,269
  • 2
  • 94
  • 81
0

use this code corner radius of view only two sides.after long time i got suggestion ios. here viewFilter is view outlet which we want rounded.

-(void) viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
[self setMaskTo:viewFilter byRoundingCorners:UIRectCornerBottomLeft | UIRectCornerBottomRight];
}

-(void)setMaskTo:(UIView*)view byRoundingCorners:(UIRectCorner)corners{

UIBezierPath *rounded = [UIBezierPathbezierPathWithRoundedRect:view.bounds byRoundingCorners:corners cornerRadii:CGSizeMake(20.0, 20.0)];

CAShapeLayer *shape = [[CAShapeLayer alloc] init];
shape.frame = self.view.bounds;
[shape setPath:rounded.CGPath];
view.layer.mask = shape;
}
Maulik Patel
  • 2,045
  • 17
  • 24
0

I don't understand why everyone writes extensions to UIView? After all, other developers will look for corner radius in CALayer. Add extension to the correct classes, otherwise other team members will never see it ((.

import UIKit

extension CALayer {
    func corner(radius: CGFloat, corners: UIRectCorner = .allCorners) {
        if #available(iOS 11.0, *) {
            masksToBounds = true
            cornerRadius = radius
            maskedCorners = corners.caCornerMask
        } else {
            let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
            let shapeLayer = CAShapeLayer()
            shapeLayer.path = path.cgPath
            mask = shapeLayer
            setNeedsDisplay()
        }
    }
}

extension UIRectCorner {
    /// convert UIRectCorner to CACornerMask
    var caCornerMask: CACornerMask {
        var cornersMask = CACornerMask()
        if self.contains(.topLeft) {
            cornersMask.insert(.layerMinXMinYCorner)
        }
        if self.contains(.topRight) {
            cornersMask.insert(.layerMaxXMinYCorner)
        }
        if self.contains(.bottomLeft) {
            cornersMask.insert(.layerMinXMaxYCorner)
        }
        if self.contains(.bottomRight) {
            cornersMask.insert(.layerMaxXMaxYCorner)
        }
        return cornersMask
    }
}

use like this

youView.layer.corner(radius: 20, corners: [.topLeft, .bottomLeft, .bottomRight])

SWIFT will suggest this method after typing youView.layer.corner and other team members will see it.

flowGlen
  • 627
  • 3
  • 11