Custom Rounding Corners on Uiview

Giving UIView rounded corners

Try this

#import <QuartzCore/QuartzCore.h> // not necessary for 10 years now  :)

...

view.layer.cornerRadius = 5;
view.layer.masksToBounds = true;

Note: If you are trying to apply rounded corners to a UIViewController's view, it should not be applied in the view controller's constructor, but rather in -viewDidLoad, after view is actually instantiated.

Swift UIView Subviews not rounding corners in Custom UIView Subclass

An easy way to make it look as expected is to add layoutIfNeeded() call inside your makeCircle(v:UIView) method. This will make you sure that all views' frames are updated correctly before applying visual changes:

func makeCircle(v:UIView) {
v.layoutIfNeeded()
v.layer.cornerRadius = v.frame.size.width * 0.50
v.clipsToBounds = true
}

UIView with shadow, rounded corners and custom drawRect

This is a tricky one. UIView's clipsToBounds is necessary to get the rounded corners. But CALayer's masksToBounds has to be false so the shadow is visible. Somehow, everything works if drawRect is not overridden, but actually it shouldn't.

The solution is to create a superview to provide the shadow (in the demonstration below this is the shadowView). You can test the following in Playground:

class MyView : UIView {
override func drawRect(rect: CGRect) {
let c = UIGraphicsGetCurrentContext()
CGContextAddRect(c, CGRectMake(10, 10, 80, 80))
CGContextSetStrokeColorWithColor(c , UIColor.redColor().CGColor)
CGContextStrokePath(c)
}
}

let superview = UIView(frame: CGRectMake(0, 0, 200, 200))

let shadowView = UIView(frame: CGRectMake(50, 50, 100, 100))
shadowView.layer.shadowColor = UIColor.blackColor().CGColor
shadowView.layer.shadowOffset = CGSizeZero
shadowView.layer.shadowOpacity = 0.5
shadowView.layer.shadowRadius = 5

let view = MyView(frame: shadowView.bounds)
view.backgroundColor = UIColor.whiteColor()
view.layer.cornerRadius = 10.0
view.layer.borderColor = UIColor.grayColor().CGColor
view.layer.borderWidth = 0.5
view.clipsToBounds = true

shadowView.addSubview(view)
superview.addSubview(shadowView)

Result:

Sample Image

Custom Rounding corners on UIView

The problem is that vwView gets resized later to fit the screen, but you don't update the path for its new size. There's no particularly trivial fix for this. You basically need to make vwView a custom class (if it's not already) and update the mask in layoutSubviews. Example:

public class RoundedBorderView: UIView {

public var roundedCorners: UIRectCorner = [ .BottomLeft, .BottomRight ] {
didSet { self.setNeedsLayout() }
}

public var cornerRadii: CGSize = CGSizeMake(10, 10) {
didSet { self.setNeedsLayout() }
}

public override func layoutSubviews() {
super.layoutSubviews()
updateMask()
}

private func updateMask() {
let mask = maskShapeLayer()
mask.path = UIBezierPath(roundedRect: bounds, byRoundingCorners: roundedCorners, cornerRadii: cornerRadii).CGPath
}

private func maskShapeLayer() -> CAShapeLayer {
if let mask = layer.mask as? CAShapeLayer {
return mask
}
let mask = CAShapeLayer()
layer.mask = mask
return mask
}

}

Change the class of vwView to RoundedBorderView and it will maintain its own mask layer.

How to set cornerRadius for only top-left and top-right corner of a UIView?

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)
}
}

UIView with rounded corners and drop shadow?

The following code snippet adds a border, border radius, and drop shadow to v, a UIView:

// border radius
[v.layer setCornerRadius:30.0f];

// border
[v.layer setBorderColor:[UIColor lightGrayColor].CGColor];
[v.layer setBorderWidth:1.5f];

// drop shadow
[v.layer setShadowColor:[UIColor blackColor].CGColor];
[v.layer setShadowOpacity:0.8];
[v.layer setShadowRadius:3.0];
[v.layer setShadowOffset:CGSizeMake(2.0, 2.0)];

Swift 5 Version :

// border radius
v.layer.cornerRadius = 30.0

// border
v.layer.borderColor = UIColor.lightGray.cgColor
v.layer.borderWidth = 1.5

// drop shadow
v.layer.shadowColor = UIColor.black.cgColor
v.layer.shadowOpacity = 0.8
v.layer.shadowRadius = 3.0
v.layer.shadowOffset = CGSize(width: 2.0, height: 2.0)

You can adjust the settings to suit your needs.

Also, add the QuartzCore framework to your project and:

#import <QuartzCore/QuartzCore.h>

See my other answer regarding masksToBounds.


Note

This may not work in all cases. If you find that this method interferes with other drawing operations that you are performing, please see this answer.

Rounded corners changes UIView size

Its because your CAShapeLayer is not automatically resizing once the Header View's constraints are being resized. You need to update the path whenever the view is resized:

  let headerView: UIView!

override func awakeFromNib() {
super.awakeFromNib()

headerView = UIView(frame: bounds)
headerView.frame = bounds

headerView.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 8).isActive = true
headerView.topAnchor.constraint(equalTo: self.topAnchor, constant: 4).isActive = true
headerView.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -8).isActive = true
headerView.heightAnchor.constraint(equalToConstant: 40).isActive = true


let rectShape = CAShapeLayer()
rectShape.bounds = headerView.layer.frame
rectShape.position = headerView.center

headerView.layer.backgroundColor = UIColor.green.cgColor
headerView.layer.mask = rectShape
}

override func layoutSubviews() {
super.layoutSubviews()

rectShape.path = UIBezierPath(roundedRect: headerView.layer.bounds, byRoundingCorners: [ .topLeft, .topRight], cornerRadii: CGSize(width: 10, height: 10)).cgPath
}

I used awakeFromNib just as an example. Your setup for your view may be different in your custom UITableViewCell class.

Round top corners of a UIView and add border

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.

Round Corners UIView in Swift 4

I've tried your code and it's working fine with iOS 11.1 & Swift 4.0. (As you have mentioned it shows you an error, but it's not showing me any error)

@IBDesignable
class RoundUIView: UIView {

@IBInspectable var borderColor: UIColor = UIColor.white {
didSet {
self.layer.borderColor = borderColor.cgColor
}
}

@IBInspectable var borderWidth: CGFloat = 2.0 {
didSet {
self.layer.borderWidth = borderWidth
}
}

@IBInspectable var cornerRadius: CGFloat = 0.0 {
didSet {
self.layer.cornerRadius = cornerRadius
}
}

}

Here is result

Sample Image



Update:

Even your updated code is working fine, also.

@IBDesignable
class DesignableView: UIView {
}

extension UIView {

@IBInspectable
var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
}
}
}

Here is result for it:

Sample Image



Related Topics



Leave a reply



Submit