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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34269399/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 08:23:44  来源:igfitidea点击:

How to control shadow spread and blur?

iosswiftuiviewcore-graphics

提问by Quantaliinuxite

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 named spread or blur, or anything equivalent (the only control was merely shadowOpacity) How can control things like blur and spread?

我在草图中设计了 UI 元素,其中一个具有模糊 1 和传播 0 的阴影。我查看了视图图层属性的文档,并且图层没有任何名为传播或模糊的东西,或任何等效的东西(唯一的控件是仅仅是shadowOpacity)如何控制模糊和扩散之类的东西?

EDIT:

编辑:

Here are my settings in Sketch : Sketch shadow settings


And here is what I want my shadow to look like:

这是我在 Sketch 中的设置: 这是我希望我的阴影的样子:草图阴影设置


Shadow wanted

影子通缉




And here is what it looks like at the moment:

Current shadow
Note, you have to click on the picture to actually see the shadow.




这是目前的样子:注意,您必须单击图片才能真正看到阴影。

当前阴影

My code is as follows:

我的代码如下:

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
}

回答by Senseful

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

以下是如何以近乎完美的精度将所有 6 个 Sketch 阴影属性应用于 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
    }
  }
}

Say we want to represent the following:

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

enter image description here

在此处输入图片说明

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:

例子:

enter image description here

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

在此处输入图片说明

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

Note:

笔记:

  • When using a non-zero spread, it hardcodes a path based on the boundsof the CALayer. If the layer's bounds ever change, you'd want to call the applySketchShadow()method again.
  • 当使用非零值时spread,它会根据boundsCALayer 的对路径进行硬编码。如果图层的边界发生变化,您需要applySketchShadow()再次调用该方法。

回答by O-mkar

You can try this .... you can play with the values. The shadowRadiusdictates the amount of blur. shadowOffsetdictates where the shadow goes.

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

Swift 2.0

斯威夫特 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

斯威夫特 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

传播示例

Example with spread

传播示例

To create a basic shadow

创建基本阴影

    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

Basic Shadow example in Swift 2.0

Swift 2.0 中的基本阴影示例

OUTPUT

输出

回答by O-mkar

Sketch Shadow Using IBDesignable and IBInspectable in Swift 4

在 Swift 4 中使用 IBDesignable 和 IBInspectable 绘制阴影

SKETCH AND XCODE SIDE BY SIDE

草图和 Xcode 并排

Shadow Exampl

影子示例

CODE

代码

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

OUTPUT

输出

DEMO OUTPUT

演示输出

HOW TO USE IT

如何使用它

DEMO

演示

回答by Cesare

This code worked very well for me:

这段代码对我来说效果很好:

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

回答by Zig

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.

我稍后会发布一些示例,但这对我来说适用于循环视图。

回答by Josep Escobar

My solution based on this post replies: (Swift 3)

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

回答by Piotr Gaw?owski

It might be a little diggin in history, but maybe some had same issue. I useed code sample from accepted answer. However the effects are quite different: - y value has to be around half compared to same value in sketch - I tried to apply shadow on navigation bar and the effect is terribly different - barely visible while using same values that sketch had.

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

So there seems that the method is totally not reflecting sketch parameters. Any hints?

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