如何控制阴影的扩散和模糊?

我已经在草图中设计了 UI 元素,其中一个元素的阴影是模糊1和扩展0。我在文档中查看了视图层的属性和图层没有任何名为扩展或模糊,或任何等价的东西(唯一的控制只是阴影不透明度)。怎样才能控制模糊和蔓延之类的东西?

以下是我在草图中的设置:

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
}
75545 次浏览

你可以试试这个... ... 你可以玩这些价值观。 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中的基本 Shadow 示例

OUTPUT

这个代码对我来说非常有效:

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

我的解决方案基于这个帖子回复: (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

下面是如何将所有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)
{
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
}
}
}

假设我们要表示以下内容:

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()方法。

在 Swift 4中使用 IBDesignable 和 IBChectable 绘制草图阴影

草图和 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

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

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

稍后我将发布一些示例,但是对于我来说,这对圆形视图非常有效。

这可能是历史上的一个小挖掘,但也许有些人有同样的问题。我使用的代码样本从接受的答案。然而,效果却截然不同: Y 值必须是素描中相同值的一半左右 - 我试着在导航条上加上阴影,效果完全不同-在使用与草图相同的值时几乎看不见。

因此,这种方法似乎完全没有反映草图参数。 有线索吗?

我非常喜欢 答案张贴在这里和评论中的建议,这就是我修改解决方案的方法:

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)

@ 理智的回答改变一点点,工作到我的项目很好。

  • 支持阴影角半径(一些圆角视图)
  • 它仍然应用阴影效果(看起来像边框)
struct SketchShadow {
var color: UIColor = .black
let alpha: Float = 0.1
let x: CGFloat
let y: CGFloat
let blur: CGFloat
let spread: CGFloat
let cornorRadius: CGFloat
    

func applyToLayer(_ layer: CALayer) {
layer.masksToBounds = false
layer.shadowColor = color.cgColor
layer.shadowOpacity = alpha
layer.shadowOffset = CGSize(width: x, height: y)
layer.shadowRadius = blur / 2.0
if spread == 0 {
layer.shadowPath = UIBezierPath(roundedRect: layer.bounds, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: cornorRadius, height: cornorRadius)).cgPath
} else {
let dx = -(spread)
let rect = layer.bounds.insetBy(dx: dx, dy: dx)
layer.shadowPath = UIBezierPath(roundedRect: rect, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: cornorRadius, height: cornorRadius)).cgPath
}
}
}