Round top corners of a UIView and add border
Swift version of David Berry's answer:
func roundCorners(corners:UIRectCorner, radius:CGFloat) {
let bounds = self.bounds
let maskPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSizeMake(radius, radius))
let maskLayer = CAShapeLayer()
maskLayer.frame = bounds
maskLayer.path = maskPath.CGPath
self.layer.mask = maskLayer
let frameLayer = CAShapeLayer()
frameLayer.frame = bounds
frameLayer.path = maskPath.CGPath
frameLayer.strokeColor = UIColor.redColor().CGColor
frameLayer.fillColor = nil
self.layer.addSublayer(frameLayer)
}
func roundTopCornersRadius(radius:CGFloat) {
self.roundCorners([UIRectCorner.TopLeft, UIRectCorner.TopRight], radius:radius)
}
func roundBottomCornersRadius(radius:CGFloat) {
self.roundCorners([UIRectCorner.BottomLeft, UIRectCorner.BottomRight], radius:radius)
}
label.layer.cornerRadius = 3.0
label.layer.maskedCorners = [.layerMinXMinYCorner,.layerMinXMaxYCorner]//round top left and bottom left corners
Source:https://www.hackingwithswift.com/example-code/calayer/how-to-round-only-specific-corners-using-maskedcorners
Image of working solution
this is probably a very late answer but I would just like to share the solution I came up with based on answers of different people from different similar questions. I got big help from Vojtech's answer above.
extension UIView {
func EZRoundCorners(corners:UIRectCorner, radius: CGFloat) -> CAShapeLayer {
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
return mask
}
func EZRoundCornersWithBorder(corners:UIRectCorner, radius:CGFloat, color:UIColor, width:CGFloat) -> CAShapeLayer {
let mask = self.EZRoundCorners(corners, radius: radius)
// Add border
let borderLayer = EZCALayer()
borderLayer.path = mask.path // Reuse the Bezier path
borderLayer.fillColor = UIColor.clearColor().CGColor
borderLayer.strokeColor = color.CGColor
borderLayer.lineWidth = width
borderLayer.frame = self.bounds
self.layer.addSublayer(borderLayer)
return borderLayer
}
func removeEZLayers () {
for layer in self.layer.sublayers! {
if layer is EZCALayer {
layer.removeFromSuperlayer()
}
}
}
}
class EZCALayer : CAShapeLayer {
}
I inherited from CAShapeLayer so I can remove the border sublayers if I don't want to use them anymore.
The mask layer doesn't get drawn, just used to compute the mask. Try:
-(void)roundCorners:(UIRectCorner)corners radius:(CGFloat)radius
{
CGRect bounds = self.bounds;
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:bounds
byRoundingCorners:corners
cornerRadii:CGSizeMake(radius, radius)];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = bounds;
maskLayer.path = maskPath.CGPath;
self.layer.mask = maskLayer;
CAShapeLayer* frameLayer = [CAShapeLayer layer];
frameLayer.frame = bounds;
frameLayer.path = maskPath.CGPath;
frameLayer.strokeColor = [UIColor redColor].CGColor;
frameLayer.fillColor = nil;
[self.layer addSublayer:frameLayer];
}
-(void)roundTopCornersRadius:(CGFloat)radius
{
[self roundCorners:(UIRectCornerTopLeft|UIRectCornerTopRight) radius:radius];
}
-(void)roundBottomCornersRadius:(CGFloat)radius
{
[self roundCorners:(UIRectCornerBottomLeft|UIRectCornerBottomRight) radius:radius];
}
The frame you're currently seeing drawn is the UITextField's normal frame, so set the frame style to none. You'll also have to adjust the insets to make up for the fact that with the frame style set to none there's normally no inset.