Несколько теней под UIView iOS Swift - PullRequest
1 голос
/ 21 марта 2019

Я пытаюсь сделать UIB-кнопку с закругленными углами с двумя цветными тенями. Почему красный (и в этот момент также синий «теневой» слой, покрывающий кнопку? Как получить тени под холстом кнопки). Я думал, что это помогает вставлять подслои, а не просто добавлять их.

Shadows are above button

Я сделал игровую площадку, иллюстрирующую проблему

import UIKit
import PlaygroundSupport

Это кнопка, которую я пытаюсь реализовать

class PrimaryButton: UIButton {
    required init(text: String = "Test 1", hasShadow: Bool = true) {
        super.init(frame: .zero)
        setTitle(text, for: .normal)
        backgroundColor = UIColor.blue
        layer.cornerRadius = 48 / 2
        layer.masksToBounds = false
        if hasShadow {
            insertShadow()
        }
    }

    fileprivate func insertShadow() {
        let layer2 = CALayer(layer: layer), layer3 = CALayer(layer: layer)
        layer2.applySketchShadow(color: UIColor.red, alpha: 0.5, x: 0, y: 15, blur: 35, spread: -10)
        layer3.applySketchShadow(color: UIColor.blue, alpha: 0.5, x: 0, y: 10, blur: 21, spread: -9)
        layer.insertSublayer(layer2, at: 0)
        layer.insertSublayer(layer3, at: 0)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        layer.sublayers?.forEach { (sublayer) in
            sublayer.shadowPath = UIBezierPath(rect: bounds).cgPath
        }
    }
}

Это расширение, которое помогает добавить тень из спецификации Sketch:

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
        }
        masksToBounds = false
    }
}


class MyViewController : UIViewController {
    override func loadView() {
        let view = UIView()
        view.backgroundColor = .white

        let button = PrimaryButton()
        button.frame = CGRect(x: 150, y: 200, width: 200, height: 48)
        view.addSubview(button)
        self.view = view
    }
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()

Ответы [ 3 ]

1 голос
/ 21 марта 2019

Измените ваши вставки на:

    layer.insertSublayer(layer2, at: 1)
    layer.insertSublayer(layer3, at: 2)

Это должно сделать это.

1 голос
/ 21 марта 2019

Мне кажется это законным.layer1 & layer2 - это подслои слоя кнопки.

Вы можете добавить третий слой, который будет служить фоном.Вот пример, основанный на вашем коде:

class PrimaryButton: UIButton {

    let layer1 = CALayer(), layer2 = CALayer(), layer3 = CALayer()

    override func layoutSubviews() {
        super.layoutSubviews()
        layer1.backgroundColor = UIColor.blue.cgColor
        layer1.cornerRadius = 48 / 2
        [layer1, layer2, layer3].forEach {
            $0.masksToBounds = false
            $0.frame = layer.bounds
            layer.insertSublayer($0, at: 0)
        }
        layer2.applySketchShadow(color: UIColor.red, alpha: 0.5, x: 0, y: 15, blur: 35, spread: -10)
        layer3.applySketchShadow(color: UIColor.blue, alpha: 0.5, x: 0, y: 10, blur: 21, spread: -9)
    }
}

Обратите внимание, что я поместил большую часть кода в layoutSubviews, потому что большинство ваших методов используют фактические границы кнопки.

0 голосов
/ 21 марта 2019

Другой способ - добавить двойные кнопки без изменения вашего класса.

    let button = PrimaryButton()
    button.frame = CGRect(x: 150, y: 200, width: 200, height: 48)
    button.backgroundColor = UIColor.clear
    view.addSubview(button)
    self.view = view
    let button1 = PrimaryButton()
    button1.frame = CGRect(x: 0, y: 0, width: 200, height: 48)
    button.addSubview(button1)
    button1.layer.sublayers?.forEach{$0.removeFromSuperlayer()}
...