Search code examples
swiftuiimageviewshadow

Swift - Creating shadow with 2 different colours for imageView


I'm wondering how to create a shadow with two different colours for an imageView. For example the top and left side has a different colour than the right and bottom side of the imageView.


Solution

  • To get different color shadows - one going up-left and one going down-right - on a UIImageView, one approach would be:

    • Subclass UIView
    • Give it 3 CALayer sublayers
      • Shadow 1 layer
      • Shadow 2 layer
      • Image layer

    This also makes it easy to add rounded corners.

    Here is a sample class. It has @IBInspectable properties to set the image, corner radius, shadow colors and shadow offsets. It is also marked @IBDesignable so you can see how it looks while designing in Storyboard / Interface Builder:

    @IBDesignable
    class DoubleShadowRoundedImageView: UIView {
        @IBInspectable var image: UIImage? = nil {
            didSet {
                imageLayer.contents = image?.cgImage
            }
        }
    
        @IBInspectable var cornerRadius: CGFloat = 0.0
    
        @IBInspectable var shad1X: CGFloat = 0.0
        @IBInspectable var shad1Y: CGFloat = 0.0
    
        @IBInspectable var shad2X: CGFloat = 0.0
        @IBInspectable var shad2Y: CGFloat = 0.0
    
        @IBInspectable var shad1Color: UIColor = UIColor.blue
        @IBInspectable var shad2Color: UIColor = UIColor.red
    
        var imageLayer: CALayer = CALayer()
        var shadowLayer1: CALayer = CALayer()
        var shadowLayer2: CALayer = CALayer()
    
        var shape: UIBezierPath {
            return UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius)
        }
    
        var shapeAsPath: CGPath {
            return shape.cgPath
        }
    
        var shapeAsMask: CAShapeLayer {
            let s = CAShapeLayer()
            s.path = shapeAsPath
            return s
        }
    
        override func layoutSubviews() {
            super.layoutSubviews()
    
            clipsToBounds = false
            backgroundColor = .clear
    
            self.layer.addSublayer(shadowLayer1)
            self.layer.addSublayer(shadowLayer2)
            self.layer.addSublayer(imageLayer)
    
            imageLayer.frame = bounds
    
            imageLayer.mask = shapeAsMask
    
            shadowLayer1.frame = bounds
            shadowLayer2.frame = bounds
    
            shadowLayer1.shadowPath = (image == nil) ? nil : shapeAsPath
            shadowLayer1.shadowOpacity = 0.80
    
            shadowLayer2.shadowPath = (image == nil) ? nil : shapeAsPath
            shadowLayer2.shadowOpacity = 0.80
    
            shadowLayer1.shadowColor = shad1Color.cgColor
            shadowLayer2.shadowColor = shad2Color.cgColor
    
            shadowLayer1.shadowOffset = CGSize(width: shad1X, height: shad1Y)
            shadowLayer2.shadowOffset = CGSize(width: shad2X, height: shad2Y)
    
        }
    }
    

    You would probably want to change some of the default values, and you might want to add some additional properties (such as shadow opacity).

    Example results:

    enter image description here