Hi i am searching a clean solution without overwriting drawRect
or stuff like that to create a UIView
with Rounded corners on the Top of the View. My main problem here is to create variable solution if the view is getting resized or something like that.
Is there a clean solution? Apple is this doing too on the first table item. it can't be so hard to do this.

- 856
- 13
- 32

- 1,195
- 1
- 12
- 26
-
1Is there a good reason you don't want to override `drawRect`? – jrturton Apr 25 '12 at 14:09
-
2because it's the last thing i want to do… its so nasty and i think there are prettier ways to do this. – mariusLAN Apr 25 '12 at 14:13
-
2drawRect ist not nasty, but the real stuff! – vikingosegundo Apr 25 '12 at 14:18
-
For anyone looking for a modern answer that also has support for borders, I added a very clean solution below - https://stackoverflow.com/a/57498969/7107094 – Trev14 Aug 14 '19 at 16:54
-
For `interface builder` only solution look here: https://stackoverflow.com/a/58626264 – Bruno Bieri Oct 30 '19 at 13:20
11 Answers
You can do this by setting a mask
on your view's layer:
CAShapeLayer * maskLayer = [CAShapeLayer layer];
maskLayer.path = [UIBezierPath bezierPathWithRoundedRect: self.bounds byRoundingCorners: UIRectCornerTopLeft | UIRectCornerTopRight cornerRadii: (CGSize){10.0, 10.}].CGPath;
self.layer.mask = maskLayer;
IMPORTANT: You should do this in your view's layoutSubviews()
method, so the view has already been resized from the storyboard
In Swift <= 1.2
let maskLayer = CAShapeLayer()
maskLayer.path = UIBezierPath(roundedRect: bounds, byRoundingCorners: .TopLeft | .TopRight, cornerRadii: CGSize(width: 10.0, height: 10.0)).CGPath
layer.mask = maskLayer
Swift 2.x
let maskLayer = CAShapeLayer()
maskLayer.path = UIBezierPath(roundedRect: bounds, byRoundingCorners: UIRectCorner.TopLeft.union(.TopRight), cornerRadii: CGSizeMake(10, 10)).CGPath
layer.mask = maskLayer
Swift 3.x
let maskLayer = CAShapeLayer()
maskLayer.path = UIBezierPath(roundedRect: view.bounds, byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width: 10, height: 10)).cgPath
layer.mask = maskLayer

- 50,474
- 16
- 129
- 160
-
1Just tried it with this one, but the backgroundcolor is now gone :( The code is 1 to 1 your code… – mariusLAN Apr 25 '12 at 14:06
-
1That's puzzling! I created a UIView subview to test this out and it worked fine. – Ashley Mills Apr 25 '12 at 14:12
-
i pasted my code here http://pastebin.com/ueG4un9T and my background color is now gone :( – mariusLAN Apr 25 '12 at 14:17
-
Is this a view that's instantiated in a nib? Or are you calling initWithFrame: in code? – Ashley Mills Apr 25 '12 at 14:38
-
i am calling my own designated init. tried it now on a different way http://pastebin.com/yiSunUYx but the background view is absolute gone too :( – mariusLAN Apr 25 '12 at 14:44
-
Are you using this in an ARC project? I wonder if it could be related to this issue... http://weblog.bignerdranch.com/?p=296 – Ashley Mills Apr 25 '12 at 15:36
-
Yeah i am using ARC in the project. And i tried the solution form the big nerd ranch but its not working at all :( thats very dissapointing, because this seems the best answer for me but it's not working. I think the Mask is so big, that the view is complete overlaid with the mask and i see nothing after applying it. – mariusLAN Apr 26 '12 at 06:41
-
To debug this, I'd try reducing the size of the mask rectangle, say to a 10x10 rect (or even 0x0) to start and see what happens. If that works, just change your code one line at time until it doesn't to figure out what's wrong. – Ashley Mills Apr 26 '12 at 09:11
-
i worked this out and got a new Solution, i will post it for others as one of the answers here. – mariusLAN May 02 '12 at 06:31
-
23
-
1@random: Has anyone had an issue with this only rounding the left corner ---> check my answer : http://stackoverflow.com/a/40222533/2594699 – Nhat Dinh Oct 25 '16 at 07:00
-
1
-
-
@user1673099 The question is "Rounded Corners only on Top of a UIView" - which is why it doesn't work on the bottom! – Ashley Mills May 05 '17 at 11:58
-
3
-
1@meaning-matters check out my post below for an example of rounded corners with border width and color - https://stackoverflow.com/a/57498969/7107094 – Trev14 Aug 14 '19 at 16:53
Modern & Easy solution
iOS 11+
Now we have the maskedCorners
property on the view's layer & it makes life much easier.
Just set your desired corner radius and specify which corners should be masked. The best part is that this plays well with borders - the layer border will follow the edge of the layer whether it's rounded or not! Try the following code in a playground (remember to open the live view by pressing command+option+return
so you can see what it looks like)
import UIKit
import PlaygroundSupport
let wrapperView = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 160))
wrapperView.backgroundColor = .lightGray
let roundedCornerView = UIView(frame: CGRect(x: 50, y: 50, width: 300, height: 60))
roundedCornerView.backgroundColor = .white
wrapperView.addSubview(roundedCornerView)
roundedCornerView.layer.cornerRadius = 10
roundedCornerView.layer.borderColor = UIColor.red.cgColor
roundedCornerView.layer.borderWidth = 1
// this is the key part - try out different corner combinations to achieve what you need
roundedCornerView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
PlaygroundPage.current.liveView = wrapperView
Here's what it looks like:

- 3,626
- 2
- 31
- 40
Just tried with Swift 3.0
, Xcode 8.0
:
REMEMBER to set your button in viewDidLayoutSubviews()
or layoutSubViews
as
@rob described here .
And when you wanna change your button background, you just need to call:
yourButton.backgroundColor = UIColor.someColour
Source:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
yourButton.layer.masksToBounds = true
yourButton.roundCorners(corners: [.topLeft,.topRight], radius: 5)
}
extension UIButton
{
func roundCorners(corners:UIRectCorner, radius: CGFloat)
{
let maskLayer = CAShapeLayer()
maskLayer.path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius)).cgPath
self.layer.mask = maskLayer
}
}
- Here is the result:
Default state:
Seleted state:
Hope this help!!
-
then you can add self.layer.masksToBounds = true inside your roundCorners function, no? – budiDino Apr 16 '17 at 06:10
For iOS11 and later you can use the view's layer property:
@property CACornerMask maskedCorners
That defines which of the four corners receives the masking when using cornerRadius property. Defaults to all four corners. (Apple doc)

- 7,169
- 1
- 44
- 45

- 1,343
- 18
- 24
-
1Good quick instructions on this here: https://www.hackingwithswift.com/example-code/calayer/how-to-round-only-specific-corners-using-maskedcorners – DesignatedNerd Feb 05 '19 at 12:58
-
2It's on the `layer` property, not directly on the view (`view.layer` from a ViewController). – Claus Jørgensen Mar 04 '19 at 16:50
An extension for UIView that rounds selected corners (Swift 4):
extension UIView {
/// Round UIView selected corners
///
/// - Parameters:
/// - corners: selected corners to round
/// - radius: round amount
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
}
}
example:
ratingView.roundCorners([.topLeft, .topRight, .bottomRight], radius: 6)

- 1,034
- 11
- 44

- 13,077
- 8
- 66
- 75
I worked this out with the help of Ashley.
First of all i subclassed a UIView. Creating a own constructor for my Class called - (id)initWithContentView:(UIView *)aView forTableView:(UITableView *)table andIndex:(NSIndexPath *)indexPath;
. In this constructor i determine what kind of table cell i am want to style.
Then i overwrite l - (void)layoutSubviews
to create the CAShapeLayer
and applying the layer mask.
.h File Code
typedef enum {
tableCellMiddle,
tableCellTop,
tableCellBottom,
tableCellSingle
} tableCellPositionValue;
@interface TableCellBackgrounds : UIView
{
tableCellPositionValue position;
}
- (id)initWithContentView:(UIView *)aView forTableView:(UITableView *)table andIndex:(NSIndexPath *)indexPath;
@end
.m File Code
- (id)initWithContentView:(UIView *)aView forTableView:(UITableView *)table andIndex:(NSIndexPath *)indexPath
{
self = [super initWithFrame:aView.frame];
[self setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
if(self)
{
[self setBackgroundColor:[UIColor colorWithRed:(float)230/255 green:(float)80/255 blue:(float)70/255 alpha:1]];
if(table.style == UITableViewStyleGrouped)
{
int rows = [table numberOfRowsInSection:indexPath.section];
if(indexPath.row == 0 && rows == 1)
{
self.layer.cornerRadius = 11;
position = tableCellSingle;
}
else if (indexPath.row == 0)
position = tableCellTop;
else if (indexPath.row != rows - 1)
position = tableCellMiddle;
else
position = tableCellBottom;
}
}
return self;
}
- (void)layoutSubviews
{
[super layoutSubviews];
if(position == tableCellTop)
{
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.path = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:UIRectCornerTopLeft|UIRectCornerTopRight cornerRadii:(CGSize){10.0, 10.0}].CGPath;
self.layer.mask = maskLayer;
}
else if (position == tableCellBottom)
{
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.path = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:UIRectCornerBottomLeft|UIRectCornerBottomRight cornerRadii:(CGSize){10.0, 10.0}].CGPath;
self.layer.mask = maskLayer;
}
}

- 1,195
- 1
- 12
- 26
-
Thank you kind sir! I needed my view's bottom portion to be curved and your code worked to perfection. Even though I have a tableView, I didn't have to do the initWithContentView though. Just the 3 lines inside else if(position==tableCellBottom) worked for me. – thandasoru Nov 24 '13 at 11:58
In Objective-C it looks like:
[oCollectionViewCell.layer setMasksToBounds:YES];
[oCollectionViewCell.layer setCornerRadius:5.0];
[oCollectionViewCell.layer setMaskedCorners:kCALayerMinXMinYCorner|kCALayerMaxXMinYCorner];

- 210
- 2
- 7
With swift 3.0 the below worked for me
let maskLayer = CAShapeLayer()
maskLayer.path = UIBezierPath(roundedRect: view.bounds, byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width: 10, height: 10)).cgPath
(imageView.)layer.mask = maskLayer
Important: Make sure this is in 'layoutSubviews' not 'awakeFromNib' (if you are using a TableViewCell) or similar ones for UIView's, or only the top left corner is rounded!

- 79
- 5
New technique
let redBox = UIView(frame: CGRect(x: 100, y: 100, width: 128, height: 128))
redBox.backgroundColor = .red
redBox.layer.cornerRadius = 25
redBox.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMaxYCorner]
view.addSubview(redBox)
Reference from Hacking With Swift

- 1,874
- 6
- 26
- 46
CAShapeLayer * maskLayer = [CAShapeLayer layer];
maskLayer.path = [UIBezierPath bezierPathWithRoundedRect: registerbtn.bounds byRoundingCorners: UIRectCornerBottomLeft | UIRectCornerBottomRight cornerRadii: (CGSize){9.0, 12.0}].CGPath;
registerbtn.layer.mask = maskLayer;
this will do only one corner rounded
The straightforward way to do this would be to define a path in the shape you want, and fill it with whatever color you want to use for the background. You might use either UIBezierPath
or CGPath
for this. Using CGPath
, for example, you can construct a path using methods such as CGMoveToPoint()
, CGAddLineToPoint()
, and CGAddArc()
. You'd then fill it with CGContextFillPath()
. Have a look at the Quartz 2D Programming Guide for a complete discussion.
Another way would be to add a subview with rounded corners (you can set the subview's layer's cornerRadius property), but let one side of the subview be clipped by the parent view.
A third way would be to add a background image with the desired shape. You can make the corners transparent and make the view's background transparent, and you'll get the desired effect. This won't work so well for resizing, though.
Where are you getting stuck?

- 124,013
- 19
- 183
- 272
-
What do you mean by Path? Can you explain it a little more detailed? – mariusLAN Apr 25 '12 at 13:47
-
Sorry, wrong answer - he asked how to do it without overriding drawRect – Ashley Mills Apr 25 '12 at 13:57
-
@AshleyMills The OP asked how to do it "...without overwriting drawRect or stuff like that..." which is pretty vague. For all we know, overriding `-initWithCoder:` also qualifies as "stuff like that." The second (and now also third) methods in my answer don't require overriding anything. The first does, but I don't think that makes the answer "wrong." – Caleb Apr 25 '12 at 14:11