【问题标题】:Shadows masks to bounds only on the left and upper side. What causes this?阴影仅在左侧和上侧遮盖边界。这是什么原因造成的?
【发布时间】:2020-06-25 10:27:17
【问题描述】:

我正在尝试实现一个允许向透明按钮添加阴影的功能。为此,我正在创建一个遮盖视图内阴影的图层。但是,我的阴影在左侧和上侧被剪裁,但在右侧和下侧没有被剪裁。

这是它的外观(这不是一个透明按钮,但它们也可以正常工作,除了像这样剪切阴影。):

这是我实现这一目标的代码:

private func applyShadow() {
    layer.masksToBounds = false

    if shouldApplyShadow && shadowLayer == nil {
        shadowLayer = CAShapeLayer()

        let shapePath = CGPath(roundedRect: bounds, cornerWidth: cornerRadi, cornerHeight: cornerRadi, transform: nil)

        shadowLayer.path = shapePath
        shadowLayer.fillColor = backgroundColor?.cgColor
        shadowLayer.shadowPath = shadowLayer.path
        shadowLayer.shadowRadius = shadowRadius ?? 8
        shadowLayer.shadowColor = (shadowColor ?? .black).cgColor
        shadowLayer.shadowOffset = shadowOffset ?? CGSize(width: 0, height: 0)
        shadowLayer.shadowOpacity = shadowOpacity ?? 0.8

        layer.insertSublayer(shadowLayer!, at: 0)

        /// If there's background color, there is no need to mask inner shadows.
        if backgroundColor != .none && !(innerShadows ?? false) {
            let maskLayer = CAShapeLayer()
            maskLayer.path = { () -> UIBezierPath in
                let path = UIBezierPath()
                path.append(UIBezierPath(cgPath: shapePath))
                path.append(UIBezierPath(rect: UIScreen.main.bounds))
                path.usesEvenOddFillRule = true
                return path
            }().cgPath

            maskLayer.fillRule = .evenOdd
            shadowLayer.mask = maskLayer
        }
    }
}

我认为这与奇偶填充规则算法有关,我不确定。但是我怎样才能克服这个剪裁问题呢?

提前致谢。

编辑: 这是应用阴影时带有边框和文本的透明按钮的外观。我不想要。

它应该是这样的。内部没有阴影,但背景颜色也很清晰。 (除了剪裁的顶部和左侧):

【问题讨论】:

  • 为什么不直接将阴影添加到按钮层而不是添加子层。
  • 添加阴影的方法有很多种...你能用透明按钮显示你希望它的外观吗(使用你的“innerShadows”?
  • 感谢您的回复。我更新了我的问题。 @kjoe 第一张图片展示了当您直接向透明层添加阴影时会发生什么。
  • @DonMag 后一张图片是我想要实现的,正如我之前所说的,唯一的问题是顶部和左侧的剪裁。不过,在这个例子中并不那么明显。但它在上面的红色按钮上可见。

标签: ios swift xcode core-graphics calayer


【解决方案1】:

我认为有几个问题...

  1. 您将UIBezierPath(rect: UIScreen.main.bounds) 附加到您的路径中,但这会将左上角置于图层的左上角...“剪裁”左上角的阴影。

  2. 如果您确实有背景颜色,则还需要剪掉这些角,否则它们会在圆角之外“溢出”。

试一试(仅稍作修改)。它被指定为 @IBDesignable,因此您可以在 Storyboard/Interface Builder 中看到它的外观(我没有将任何属性设置为可检查的——如果您愿意,我会留给您):

@IBDesignable
class MyRSButton: UIButton {

    var shouldApplyShadow: Bool = true
    var innerShadows: Bool?

    var cornerRadi: CGFloat = 8.0

    var shadowLayer: CAShapeLayer!
    var shadowRadius: CGFloat?
    var shadowColor: UIColor?
    var shadowOffset: CGSize?
    var shadowOpacity: Float?

    override func layoutSubviews() {
        super.layoutSubviews()
        applyShadow()
    }

    private func applyShadow() {

        // needed to prevent background color from bleeding past
        // the rounded corners
        cornerRadi = bounds.size.height * 0.5
        layer.cornerRadius = cornerRadi

        layer.masksToBounds = false

        if shouldApplyShadow && shadowLayer == nil {
            shadowLayer = CAShapeLayer()

            let shapePath = CGPath(roundedRect: bounds, cornerWidth: cornerRadi, cornerHeight: cornerRadi, transform: nil)

            shadowLayer.path = shapePath
            shadowLayer.fillColor = backgroundColor?.cgColor
            shadowLayer.shadowPath = shadowLayer.path
            shadowLayer.shadowRadius = shadowRadius ?? 8
            shadowLayer.shadowColor = (shadowColor ?? .black).cgColor
            shadowLayer.shadowOffset = shadowOffset ?? CGSize(width: 0, height: 0)
            shadowLayer.shadowOpacity = shadowOpacity ?? 0.8

            layer.insertSublayer(shadowLayer!, at: 0)

            /// If there's background color, there is no need to mask inner shadows.
            if backgroundColor != .none && !(innerShadows ?? false) {
                let maskLayer = CAShapeLayer()
                maskLayer.path = { () -> UIBezierPath in
                    let path = UIBezierPath()
                    path.append(UIBezierPath(cgPath: shapePath))

                    // define a rect that is 80-pts wider and taller
                    // than the button... this will "expand" it from center
                    let r = bounds.insetBy(dx: -40, dy: -40)

                    path.append(UIBezierPath(rect: r))

                    path.usesEvenOddFillRule = true
                    return path
                    }().cgPath

                maskLayer.fillRule = .evenOdd
                shadowLayer.mask = maskLayer
            }
        }

    }

}

结果:

【讨论】:

  • 感谢@DonMag!这实际上是一个小解决方法,但它在 %99 的时间里解决了我的问题。
猜你喜欢
  • 2011-06-22
  • 2012-08-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多