I’ve been working on an application for a couple of years and received a simple design request: Round the corners on a UIView and add a drop shadow.To do as given below.
I want a custom UIView
... : I just wanted a blank white view with rounded corners and a light drop shadow (with no lighting effect). I can do each of those one by one but the usual clipToBounds
/maskToBounds
conflicts occur.
Add subview with the same color which will be centered on the parent and will be with several pixels smaller. Like this you will have space from each side of the parent. On the parent turn on clipping subviews and add shadow to the inner view. Like this, you can have an inner shadow.
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.
// corner radius blueView.layer.cornerRadius = 10 // border blueView.layer.borderWidth = 1.0 blueView.layer.borderColor = UIColor.black.cgColor // shadow blueView.layer.shadowColor = UIColor.black.cgColor blueView.layer.shadowOffset = CGSize(width: 3, height: 3) blueView.layer.shadowOpacity = 0.7 blueView.layer.shadowRadius = 4.0
What if there are sublayers or subviews (like an image) whose content we want to clip to the bounds of our view?
We can accomplish this with
blueView.layer.masksToBounds = true
(Alternatively, blueView.clipsToBounds = true
gives the same result.)
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 view baseView.backgroundColor = UIColor.clear baseView.layer.shadowColor = UIColor.black.cgColor baseView.layer.shadowOffset = CGSize(width: 3, height: 3) baseView.layer.shadowOpacity = 0.7 baseView.layer.shadowRadius = 4.0 // add the border to subview let borderView = UIView() borderView.frame = baseView.bounds borderView.layer.cornerRadius = 10 borderView.layer.borderColor = UIColor.black.cgColor borderView.layer.borderWidth = 1.0 borderView.layer.masksToBounds = true baseView.addSubview(borderView) // add any other subcontent that you want clipped let otherSubContent = UIImageView() otherSubContent.image = UIImage(named: "lion") otherSubContent.frame = borderView.bounds borderView.addSubview(otherSubContent)
This gives the following result:
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).cgPath baseView.layer.shouldRasterize = true baseView.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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With