UIView with rounded corners and drop shadow? UIView with rounded corners and drop shadow? ios ios

UIView with rounded corners and drop shadow?


Swift

enter image description here

// corner radiusblueView.layer.cornerRadius = 10// borderblueView.layer.borderWidth = 1.0blueView.layer.borderColor = UIColor.black.cgColor// shadowblueView.layer.shadowColor = UIColor.black.cgColorblueView.layer.shadowOffset = CGSize(width: 3, height: 3)blueView.layer.shadowOpacity = 0.7blueView.layer.shadowRadius = 4.0

Exploring the options

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

Problem 1: Shadow gets clipped off

What if there are sublayers or subviews (like an image) whose content we want to clip to the bounds of our view?

enter image description here

We can accomplish this with

blueView.layer.masksToBounds = true

(Alternatively, blueView.clipsToBounds = true gives the same result.)

enter image description here

But, oh no! The shadow was also clipped off because it's outside of the bounds! What to do? What to do?

Solution

Use separate views for the shadow and the border. The base view is transparent and has the shadow. The border view clips any other subcontent that it has to its borders.

// add the shadow to the base viewbaseView.backgroundColor = UIColor.clearbaseView.layer.shadowColor = UIColor.black.cgColorbaseView.layer.shadowOffset = CGSize(width: 3, height: 3)baseView.layer.shadowOpacity = 0.7baseView.layer.shadowRadius = 4.0// add the border to subviewlet borderView = UIView()borderView.frame = baseView.boundsborderView.layer.cornerRadius = 10borderView.layer.borderColor = UIColor.black.cgColorborderView.layer.borderWidth = 1.0borderView.layer.masksToBounds = truebaseView.addSubview(borderView)// add any other subcontent that you want clippedlet otherSubContent = UIImageView()otherSubContent.image = UIImage(named: "lion")otherSubContent.frame = borderView.boundsborderView.addSubview(otherSubContent)

This gives the following result:

enter image description here

Problem 2: Poor performance

Adding rounded corners and shadows can be a performance hit. You can improve performance by using a predefined path for the shadow and also specifying that it be rasterized. The following code can be added to the example above.

baseView.layer.shadowPath = UIBezierPath(roundedRect: baseView.bounds, cornerRadius: 10).cgPathbaseView.layer.shouldRasterize = truebaseView.layer.rasterizationScale = UIScreen.main.scale

See this post for more details. See here and here also.

This answer was tested with Swift 4 and Xcode 9.


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 radiusv.layer.cornerRadius = 30.0// borderv.layer.borderColor = UIColor.lightGray.cgColorv.layer.borderWidth = 1.5// drop shadowv.layer.shadowColor = UIColor.black.cgColorv.layer.shadowOpacity = 0.8v.layer.shadowRadius = 3.0v.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.


Check out the example project on GitHub to make sure you use the component correctly.

Simple Swift 5 solution without any additional subviews or subclassing:

extension UIView {    func addShadow(offset: CGSize, color: UIColor, radius: CGFloat, opacity: Float) {        layer.masksToBounds = false        layer.shadowOffset = offset        layer.shadowColor = color.cgColor        layer.shadowRadius = radius        layer.shadowOpacity = opacity        let backgroundCGColor = backgroundColor?.cgColor        backgroundColor = nil        layer.backgroundColor =  backgroundCGColor    }}

Note that you should set up your view with corner radius and other properties before calling addShadow.

After that, just call this from viewDidLoad like this:

button.addShadow(offset: CGSize.init(width: 0, height: 3), color: UIColor.black, radius: 2.0, opacity: 0.35)

Final result:

result

Super easy and simple!