如何控制阴影传播和模糊?

时间:2015-12-14 14:27:22

标签: ios swift uiview core-graphics

我在草图中设计了UI元素,其中一个具有模糊1和展开0的阴影。我查看了视图图层属性的文档,图层没有任何名为spread或blur的内容,或任何等效的内容(只控制只是shadowOpacity)如何控制模糊和传播等事情?

编辑:

以下是Sketch中的设置: Sketch shadow settings


这就是我希望我的影子看起来像:

Shadow wanted




这就是目前的样子:

Current shadow
注意,你必须点击图片才能真正看到阴影。

我的代码如下:

func setupLayer(){
    view.layer.cornerRadius = 2
    view.layer.shadowColor = Colors.Shadow.CGColor
    view.layer.shadowOffset = CGSize(width: 0, height: 1)
    view.layer.shadowOpacity = 0.9
    view.layer.shadowRadius = 5
}

8 个答案:

答案 0 :(得分:181)

以下是如何将所有6个草图阴影属性应用于UIView的图层,并且几乎完全准确:

extension CALayer {
  func applySketchShadow(
    color: UIColor = .black,
    alpha: Float = 0.5,
    x: CGFloat = 0,
    y: CGFloat = 2,
    blur: CGFloat = 4,
    spread: CGFloat = 0)
  {
    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
    }
  }
}

假设我们想要代表以下内容:

enter image description here

您可以通过以下方式轻松完成此操作:

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

或更简洁:

myView.layer.applySketchShadow(y: 0)

示例:

  

enter image description here

     

左:iPhone 8 UIView截图;右:草图矩形。

注意:

  • 使用非零spread时,它会根据CALayer的bounds对路径进行硬编码。如果图层的边界发生变化,您需要再次调用applySketchShadow()方法。

答案 1 :(得分:56)

你可以尝试这个......你可以玩这些值。 shadowRadius决定了模糊量。 shadowOffset指示阴影的去向。

  

Swift 2.0

let radius: CGFloat = demoView.frame.width / 2.0 //change it to .height if you need spread for height
let shadowPath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 2.1 * radius, height: demoView.frame.height))
//Change 2.1 to amount of spread you need and for height replace the code for height

demoView.layer.cornerRadius = 2
demoView.layer.shadowColor = UIColor.blackColor().CGColor
demoView.layer.shadowOffset = CGSize(width: 0.5, height: 0.4)  //Here you control x and y
demoView.layer.shadowOpacity = 0.5
demoView.layer.shadowRadius = 5.0 //Here your control your blur
demoView.layer.masksToBounds =  false
demoView.layer.shadowPath = shadowPath.CGPath
  

Swift 3.0

let radius: CGFloat = demoView.frame.width / 2.0 //change it to .height if you need spread for height 
let shadowPath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 2.1 * radius, height: demoView.frame.height)) 
//Change 2.1 to amount of spread you need and for height replace the code for height

demoView.layer.cornerRadius = 2
demoView.layer.shadowColor = UIColor.black.cgColor
demoView.layer.shadowOffset = CGSize(width: 0.5, height: 0.4)  //Here you control x and y
demoView.layer.shadowOpacity = 0.5
demoView.layer.shadowRadius = 5.0 //Here your control your blur
demoView.layer.masksToBounds =  false
demoView.layer.shadowPath = shadowPath.cgPath
  

传播示例

Example with spread

  

创建基本阴影

    demoView.layer.cornerRadius = 2
    demoView.layer.shadowColor = UIColor.blackColor().CGColor
    demoView.layer.shadowOffset = CGSizeMake(0.5, 4.0); //Here your control your spread
    demoView.layer.shadowOpacity = 0.5 
    demoView.layer.shadowRadius = 5.0 //Here your control your blur
  

Swift 2.0中的基本阴影示例

OUTPUT

答案 2 :(得分:6)

这段代码对我很有用:

yourView.layer.shadowOpacity = 0.2 // opacity, 20%
yourView.layer.shadowColor = UIColor.black.cgColor
yourView.layer.shadowRadius = 2 // HALF of blur
yourView.layer.shadowOffset = CGSize(width: 0, height: 2) // Spread x, y
yourView.layer.masksToBounds =  false

答案 3 :(得分:6)

在Swift 4中使用IBDesignable和IBInspectable素描阴影

  

逐边素描和XCODE

Shadow Exampl

  

代码

@IBDesignable class ShadowView: UIView {

    @IBInspectable var shadowColor: UIColor? {
        get {
            if let color = layer.shadowColor {
                return UIColor(cgColor: color)
            }
            return nil
        }
        set {
            if let color = newValue {
                layer.shadowColor = color.cgColor
            } else {
                layer.shadowColor = nil
            }
        }
    }

    @IBInspectable var shadowOpacity: Float {
        get {
            return layer.shadowOpacity
        }
        set {
            layer.shadowOpacity = newValue
        }
    }

    @IBInspectable var shadowOffset: CGPoint {
        get {
            return CGPoint(x: layer.shadowOffset.width, y:layer.shadowOffset.height)
        }
        set {
            layer.shadowOffset = CGSize(width: newValue.x, height: newValue.y)
        }

     }

    @IBInspectable var shadowBlur: CGFloat {
        get {
            return layer.shadowRadius
        }
        set {
            layer.shadowRadius = newValue / 2.0
        }
    }

    @IBInspectable var shadowSpread: CGFloat = 0 {
        didSet {
            if shadowSpread == 0 {
                layer.shadowPath = nil
            } else {
                let dx = -shadowSpread
                let rect = bounds.insetBy(dx: dx, dy: dx)
                layer.shadowPath = UIBezierPath(rect: rect).cgPath
            }
        }
    }
}
  

输出

DEMO OUTPUT

  

如何使用它

DEMO

答案 4 :(得分:1)

我的解决方案基于这篇文章回复:( Swift 3)

let shadowPath = UIBezierPath(rect: CGRect(x: -1,
                                           y: -2,
                                           width: target.frame.width + 2,
                                           height: target.frame.height + 2))

target.layer.shadowColor = UIColor(hexString: shadowColor).cgColor
target.layer.shadowOffset = CGSize(width: CGFloat(shadowOffsetX), height: CGFloat(shadowOffsetY))
target.layer.masksToBounds = false
target.layer.shadowOpacity = Float(shadowOpacity)
target.layer.shadowPath = shadowPath.cgPath

答案 5 :(得分:1)

对于那些试图将阴影应用于预定义路径(例如,像圆形视图)的人,这就是我的最终结论:

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
    }
}

稍后我将发布一些示例,但这已经可以为我提供圆形视图了。

答案 6 :(得分:0)

这在历史上可能是个小问题,但也许有些人有同样的问题。我使用了可接受答案中的代码示例。但是效果却大不相同:  -与草图中的相同值相比,y值必须约为一半  -我尝试在导航栏上应用阴影,效果却大不相同-使用与草图相同的值几乎看不到。

因此,该方法似乎完全不反映草图参数。 有提示吗?

答案 7 :(得分:0)

我非常喜欢the answer posted here和评论中的建议。这就是我修改该解决方案的方式:

extension UIView {
  func applyShadow(color: UIColor, alpha: Float, x: CGFloat, y: CGFloat, blur: CGFloat, spread: CGFloat) {
    layer.masksToBounds = false
    layer.shadowColor = color.cgColor
    layer.shadowOpacity = alpha
    layer.shadowOffset = CGSize(width: x, height: y)
    layer.shadowRadius = blur / UIScreen.main.scale
    if spread == 0 {
      layer.shadowPath = nil
    } else {
      let dx = -spread
      let rect = bounds.insetBy(dx: dx, dy: dx)
      layer.shadowPath = UIBezierPath(rect: rect).cgPath
    }
  }
}

用法:

myButton.applyShadow(color: .black, alpha: 0.2, x: 0, y: 1, blur: 2, spread: 0)