Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Round some corners of UIView and round the view’s layer’s border too

I am trying to round the bottom two corners of a UIView, and have the layer’s border show up rounded as well. I am currently doing:

UIRectCorners corners = UIRectCornerBottomLeft | UIRectCornerBottomRight;
CGSize radii = CGSizeMake(kThisViewCornerRadius, kThisViewCornerRadius);
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:myView.bounds
                                           byRoundingCorners:corners
                                                 cornerRadii:radii];

CAShapeLayer *maskLayer = [CAShapeLayer layer];
[maskLayer setPath:path.CGPath];
myView.layer.mask = maskLayer;

This works fine for normal views. However, myView’s layer has its borderColor and borderWidth set, and as you can see from the screenshot, the layer’s border is not getting rounded:

Screenshot of the problem

I also tried subclassing UIView and returning [CAShapeLayer layer] from +[Class layerClass], and setting up the view’s layer as a shape layer, but the border ended up beneath the view’s subviews.

Is it possible to round some of a view’s corners, round the view’s layer’s border, and clip the subviews underneath the layer’s border?

Note that this is not about how to round some corners and not others, but rather how to get the stroke to behave correctly.

like image 914
Zev Eisenberg Avatar asked Feb 14 '13 01:02

Zev Eisenberg


People also ask

How do you round UIView corners?

If you start with a regular UIView it has square corners. You can give it round corners by changing the cornerRadius property of the view's layer . and smaller values give less rounded corners. Both clipsToBounds and masksToBounds are equivalent.

How do you round the top corner of UIView in Swift?

You can set the cornerRadius property of any UIView to have its edges rounded, but by default that rounds all corners at the same time.


2 Answers

I figured out a new way of thinking about it, thanks to David Rönnqvist’s comment.

I was trying to do the corner rounding and the stroke all in one layer. Instead, I broke it up into two layers: one to mask the view’s layer to round the corners, and the other in a view to add the stroke.

UIView *containerView = [[UIView alloc] initWithFrame:someFrame];

UIRectCorners corners = UIRectCornerBottomLeft | UIRectCornerBottomRight;
CGSize radii = CGSizeMake(kThisViewCornerRadius, kThisViewCornerRadius);

UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:myView.bounds
                                           byRoundingCorners:corners
                                                 cornerRadii:radii];

// Mask the container view’s layer to round the corners.
CAShapeLayer *cornerMaskLayer = [CAShapeLayer layer];
[cornerMaskLayer setPath:path.CGPath];
containerView.layer.mask = cornerMaskLayer;

// Make a transparent, stroked layer which will dispay the stroke.
CAShapeLayer *strokeLayer = [CAShapeLayer layer];
strokeLayer.path = path.CGPath;
strokeLayer.fillColor = [UIColor clearColor].CGColor;
strokeLayer.strokeColor = [UIColor redColor].CGColor;
strokeLayer.lineWidth = 2; // the stroke splits the width evenly inside and outside,
                           // but the outside part will be clipped by the containerView’s mask.

// Transparent view that will contain the stroke layer
UIView *strokeView = [[UIView alloc] initWithFrame:containerView.bounds];
strokeView.userInteractionEnabled = NO; // in case your container view contains controls
[strokeView.layer addSublayer:strokeLayer];

// configure and add any subviews to the container view

// stroke view goes in last, above all the subviews
[containerView addSubview:strokeView];
like image 172
Zev Eisenberg Avatar answered Sep 29 '22 01:09

Zev Eisenberg


Zev Eisenberg's answer is the right one.

Although I prefer:

[self.layer addSublayer:strokeLayer];

instead of creating and adding a subview:

CGSize radii = CGSizeMake(radius, radius);

UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:self.bounds
                                           byRoundingCorners:corners
                                                 cornerRadii:radii];

// Mask the container view’s layer to round the corners.
CAShapeLayer *cornerMaskLayer = [CAShapeLayer layer];
[cornerMaskLayer setPath:path.CGPath];
self.layer.mask = cornerMaskLayer;

// Make a transparent, stroked layer which will dispay the stroke.
CAShapeLayer *strokeLayer = [CAShapeLayer layer];
strokeLayer.path = path.CGPath;
strokeLayer.fillColor = [UIColor clearColor].CGColor;
strokeLayer.strokeColor = color.CGColor;
strokeLayer.lineWidth = 2; // the stroke splits the width evenly inside and outside,
// but the outside part will be clipped by the containerView’s mask.

[self.layer addSublayer:strokeLayer];
like image 42
Andrei Radulescu Avatar answered Sep 29 '22 02:09

Andrei Radulescu