How to control shadow spread and blur?

前端 未结 8 1147
终归单人心
终归单人心 2020-12-07 06:51

I have designed UI elements in sketch, and one of them has a shadow with blur 1 and spread 0. I looked at the doc for the views layer property and layer doesnt have anything

相关标签:
8条回答
  • 2020-12-07 07:30

    Here's how to apply all 6 Sketch shadow properties to a UIView's layer with near perfect accuracy:

    extension CALayer {
      func applySketchShadow(
        color: UIColor = .black,
        alpha: Float = 0.5,
        x: CGFloat = 0,
        y: CGFloat = 2,
        blur: CGFloat = 4,
        spread: CGFloat = 0)
      {
        masksToBounds = false
        shadowColor = color.cgColor
        shadowOpacity = alpha
        shadowOffset = CGSize(width: x, height: y)
        shadowRadius = blur / 2.0
        if spread == 0 {
          shadowPath = nil
        } else {
          let dx = -spread
          let rect = bounds.insetBy(dx: dx, dy: dx)
          shadowPath = UIBezierPath(rect: rect).cgPath
        }
      }
    }
    

    Say we want to represent the following:

    You can easily do this via:

    myView.layer.applySketchShadow(
      color: .black, 
      alpha: 0.5, 
      x: 0, 
      y: 0, 
      blur: 4, 
      spread: 0)
    

    or more succinctly:

    myView.layer.applySketchShadow(y: 0)
    

    Example:

    Left: iPhone 8 UIView screenshot; right: Sketch rectangle.

    Note:

    • When using a non-zero spread, it hardcodes a path based on the bounds of the CALayer. If the layer's bounds ever change, you'd want to call the applySketchShadow() method again.
    0 讨论(0)
  • 2020-12-07 07:33

    For those who are attempting to apply a shadow to a predefined path (Like for a circular view, for instance), here's what I ended up with:

    extension CALayer {
        func applyShadow(color: UIColor = .black,
                         alpha: Float = 0.5,
                         x: CGFloat = 0,
                         y: CGFloat = 2,
                         blur: CGFloat = 4,
                         spread: CGFloat = 0,
                         path: UIBezierPath? = nil) {
            shadowColor = color.cgColor
            shadowOpacity = alpha
            shadowRadius = blur / 2
            if let path = path {
                if spread == 0 {
                    shadowOffset = CGSize(width: x, height: y)
                } else {
                    let scaleX = (path.bounds.width + (spread * 2)) / path.bounds.width
                    let scaleY = (path.bounds.height + (spread * 2)) / path.bounds.height
    
                    path.apply(CGAffineTransform(translationX: x + -spread, y: y + -spread).scaledBy(x: scaleX, y: scaleY))
                    shadowPath = path.cgPath
                }
            } else {
                shadowOffset = CGSize(width: x, height: y)
                if spread == 0 {
                    shadowPath = nil
                } else {
                    let dx = -spread
                    let rect = bounds.insetBy(dx: dx, dy: dx)
                    shadowPath = UIBezierPath(rect: rect).cgPath
                }
            }
            shouldRasterize = true
            rasterizationScale = UIScreen.main.scale
        }
    }
    

    I'll post some examples later, but this has worked spot on for circular views for me.

    0 讨论(0)
提交回复
热议问题