I have to create a custom UIView
that will have round corners, a border, a shadow and its drawRect()
method is overridden to provide custom drawing
I find the following link helpful to understand setting the dropshadow:
How to add a shadow to a UIView
To set the round corner for UIVIEW just set the layer.cornerRadius
value in interface builder, Please check screenshot.
you can use this function for your all views.
extension UIView{
func radiusAndBorder(radius:CGFloat, color:UIColor = UIColor.clear) -> UIView{
var rounfView:UIView = self
rounfView.layer.cornerRadius = CGFloat(radius)
rounfView.layer.borderWidth = 1
rounfView.layer.borderColor = color.cgColor
rounfView.clipsToBounds = true
return rounfView
}
}
I wrote a small extension to UIView to manage both rounded corners AND drop shadow. As the variables are @IBInspectable, everything can be set directly in the storyboard !
//
// UIView extensions.swift
//
// Created by Frédéric ADDA on 25/07/2016.
// Copyright © 2016 Frédéric ADDA. All rights reserved.
//
import UIKit
extension UIView {
@IBInspectable var shadow: Bool {
get {
return layer.shadowOpacity > 0.0
}
set {
if newValue == true {
self.addShadow()
}
}
}
@IBInspectable var cornerRadius: CGFloat {
get {
return self.layer.cornerRadius
}
set {
self.layer.cornerRadius = newValue
// Don't touch the masksToBound property if a shadow is needed in addition to the cornerRadius
if shadow == false {
self.layer.masksToBounds = true
}
}
}
func addShadow(shadowColor: CGColor = UIColor.black.cgColor,
shadowOffset: CGSize = CGSize(width: 1.0, height: 2.0),
shadowOpacity: Float = 0.4,
shadowRadius: CGFloat = 3.0) {
layer.shadowColor = shadowColor
layer.shadowOffset = shadowOffset
layer.shadowOpacity = shadowOpacity
layer.shadowRadius = shadowRadius
}
}
And this is how it looks in the storyboard :
The result :
There is one requirement : DON'T touch either clipToBounds on the view (in code or in IB) or masksToBound on the layer.
NB: one case in which it won't work : tableViews.
As UITableView automatically triggers clipToBounds
under the hood, we can't have a drop shadow.
EDIT: as Claudia Fitero aptly noticed, you need to leave a small padding around the view to which you are adding a shadow, otherwise the shadow won't be visible. A 2px-padding is enough generally (depending on your shadow radius).
Swift 3
I made an UIView extension and its basically the same idea suggested by Mundi:
extension UIView {
func addShadowView() {
//Remove previous shadow views
superview?.viewWithTag(119900)?.removeFromSuperview()
//Create new shadow view with frame
let shadowView = UIView(frame: frame)
shadowView.tag = 119900
shadowView.layer.shadowColor = UIColor.black.cgColor
shadowView.layer.shadowOffset = CGSize(width: 2, height: 3)
shadowView.layer.masksToBounds = false
shadowView.layer.shadowOpacity = 0.3
shadowView.layer.shadowRadius = 3
shadowView.layer.shadowPath = UIBezierPath(rect: bounds).cgPath
shadowView.layer.rasterizationScale = UIScreen.main.scale
shadowView.layer.shouldRasterize = true
superview?.insertSubview(shadowView, belowSubview: self)
}}
Use:
class MyCVCell: UICollectionViewCell {
@IBOutlet weak var containerView: UIView!
override func awakeFromNib() {
super.awakeFromNib()
}
override func draw(_ rect: CGRect) {
super.draw(rect)
containerView.addShadowView()
}}
SWIFT 3 Solution
Adapted from Mundi's answer
class MyView : UIView {
override func draw(_ rect: CGRect) {
let c = UIGraphicsGetCurrentContext()
c!.addRect(CGRect(x: 10, y: 10, width: 80, height: 80))
c!.setStrokeColor(UIColor.red.cgColor)
c!.strokePath()
}
}
let superview = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
let shadowView = UIView(frame: CGRect(x: 50, y: 50, width: 100, height: 100))
shadowView.layer.shadowColor = UIColor.black.cgColor
shadowView.layer.shadowOffset = CGSize.zero
shadowView.layer.shadowOpacity = 0.5
shadowView.layer.shadowRadius = 5
let view = MyView(frame: shadowView.bounds)
view.backgroundColor = UIColor.white
view.layer.cornerRadius = 10.0
view.layer.borderColor = UIColor.gray.cgColor
view.layer.borderWidth = 0.5
view.clipsToBounds = true
shadowView.addSubview(view)
superview.addSubview(shadowView)
I use this extension to UIView
:
Import UIKit
extension UIView {
/// A property that accesses the backing layer's opacity.
@IBInspectable
open var opacity: Float {
get {
return layer.opacity
}
set(value) {
layer.opacity = value
}
}
/// A property that accesses the backing layer's shadow
@IBInspectable
open var shadowColor: UIColor? {
get {
guard let v = layer.shadowColor else {
return nil
}
return UIColor(cgColor: v)
}
set(value) {
layer.shadowColor = value?.cgColor
}
}
/// A property that accesses the backing layer's shadowOffset.
@IBInspectable
open var shadowOffset: CGSize {
get {
return layer.shadowOffset
}
set(value) {
layer.shadowOffset = value
}
}
/// A property that accesses the backing layer's shadowOpacity.
@IBInspectable
open var shadowOpacity: Float {
get {
return layer.shadowOpacity
}
set(value) {
layer.shadowOpacity = value
}
}
/// A property that accesses the backing layer's shadowRadius.
@IBInspectable
open var shadowRadius: CGFloat {
get {
return layer.shadowRadius
}
set(value) {
layer.shadowRadius = value
}
}
/// A property that accesses the backing layer's shadowPath.
@IBInspectable
open var shadowPath: CGPath? {
get {
return layer.shadowPath
}
set(value) {
layer.shadowPath = value
}
}
/// A property that accesses the layer.cornerRadius.
@IBInspectable
open var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set(value) {
layer.cornerRadius = value
}
}
/// A property that accesses the layer.borderWith.
@IBInspectable
open var borderWidth: CGFloat {
get {
return layer.borderWidth
}
set(value) {
layer.borderWidth = value
}
}
/// A property that accesses the layer.borderColor property.
@IBInspectable
open var borderColor: UIColor? {
get {
guard let v = layer.borderColor else {
return nil
}
return UIColor(cgColor: v)
}
set(value) {
layer.borderColor = value?.cgColor
}
}
}