Search code examples
iosswiftuiviewshadow

Adding inner shadow to top of UIView


I looked up but I couldn't find how I can add an inner shadow to UIView, only top (from top to bottom) for Swift. What is the best way add inner circle in Swift?

Edit: I've found some questions & answers on SO however they are either in obj-c or looks so complicated. I was just looking for a more Swifty way, if there is any

What I want to achieve:

enter image description here


Solution

  • Here's a pure Swift version that I whipped up:

    public class EdgeShadowLayer: CAGradientLayer {
    
        public enum Edge {
            case Top
            case Left
            case Bottom
            case Right
        }
    
        public init(forView view: UIView,
                    edge: Edge = Edge.Top,
                    shadowRadius radius: CGFloat = 20.0,
                    toColor: UIColor = UIColor.white,
                    fromColor: UIColor = UIColor.black) {
            super.init()
            self.colors = [fromColor.cgColor, toColor.cgColor]
            self.shadowRadius = radius
    
            let viewFrame = view.frame
    
            switch edge {
                case .Top:
                    startPoint = CGPoint(x: 0.5, y: 0.0)
                    endPoint = CGPoint(x: 0.5, y: 1.0)
                    self.frame = CGRect(x: 0.0, y: 0.0, width: viewFrame.width, height: shadowRadius)
                case .Bottom:
                    startPoint = CGPoint(x: 0.5, y: 1.0)
                    endPoint = CGPoint(x: 0.5, y: 0.0)
                    self.frame = CGRect(x: 0.0, y: viewFrame.height - shadowRadius, width: viewFrame.width, height: shadowRadius)
                case .Left:
                    startPoint = CGPoint(x: 0.0, y: 0.5)
                    endPoint = CGPoint(x: 1.0, y: 0.5)
                    self.frame = CGRect(x: 0.0, y: 0.0, width: shadowRadius, height: viewFrame.height)
                case .Right:
                    startPoint = CGPoint(x: 1.0, y: 0.5)
                    endPoint = CGPoint(x: 0.0, y: 0.5)
                    self.frame = CGRect(x: viewFrame.width - shadowRadius, y: 0.0, width: shadowRadius, height: viewFrame.height)
            }
        }
    
        required public init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }   
    }
    

    To use it,

    let topShadow = EdgeShadowLayer(forView: targetView, edge: .Top)
    targetView.layer.addSublayer(topShadow)
    

    Note that it defaults to a black-to-white gradient that's 20 points deep.

    The full code, with a sample UIViewController that lets you toggle shadows on all four corners of a view, can be found at https://github.com/jrtibbetts/Tenebrae. I've also documented the EdgeShadowLayer pretty thoroughly.