Kyaw Siesein
Kyaw Siesein

Reputation: 725

Adding multiple shadows hides the background colour and text UIButton

I was trying to add multiple shadows to my UIButton. The two shadows were added as you can see in the image. However, they hide the title and background colour of UIButton. Why is this happening? So, has the order of the layers become bottomLayer, topLayer, text and background?

The actual result

enter image description here

The expected Result

enter image description here

This is how my UIButton class looks.

class PrimaryButton: UIButton {
    
    let cornerRadius: CGFloat = 10
    
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    convenience init() {
        self.init(frame: .zero)
        configure()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        addDropShadow()
    }
    
    private func configure() {
        backgroundColor = .white;
        layer.cornerRadius = cornerRadius
        
        setTitle("Get Followers", for: .normal)
        setTitleColor(Colours.buttonTextColour, for: .normal)
    }

    private func addDropShadow() {
        let topLayer = createShadowLayer(color: Colours.shadowWhite, offset: CGSize(width: -6, height: -6))
        let bottomLayer = createShadowLayer(color: Colours.shadowBlack, offset: CGSize(width: 6, height: 6))
        
        layer.addSublayer(topLayer)
        layer.addSublayer(bottomLayer)
    }
    
    private func createShadowLayer(color: UIColor, offset: CGSize) -> CALayer {
        let shadowLayer = CALayer()
        shadowLayer.masksToBounds = false
        shadowLayer.shadowColor = color.cgColor
        shadowLayer.shadowOpacity = 1
        shadowLayer.shadowOffset = offset
        shadowLayer.shadowRadius = 10
        shadowLayer.shouldRasterize = true
        shadowLayer.shadowPath = UIBezierPath(roundedRect: self.bounds, cornerRadius: 10).cgPath
        
        return shadowLayer
    }
    
}

Upvotes: 1

Views: 1167

Answers (2)

shariebg
shariebg

Reputation: 109

I was able to solve the problem as follows:

Instead of adding the layers with the addSublayer(_ layer: CALayer) method, I used the insertSublayer(_ layer: CALayer, at idx: UInt32) method.

private func addDropShadow() {
        let topLayer = createShadowLayer(color: Colours.shadowWhite, offset: CGSize(width: -6, height: -6))
        let bottomLayer = createShadowLayer(color: Colours.shadowBlack, offset: CGSize(width: 6, height: 6))

        // Modified
        layer.insertSublayer(topLayer, at: 0)
        layer.insertSublayer(bottomLayer, at: 0)
    }

Also, in your createShadowLayer method, instead of CALayer, I returned a CAShapeLayer.

private func createShadowLayer(color: UIColor, offset: CGSize) -> CAShapeLayer {
        // Modified
        let shadowLayer = CAShapeLayer()
        shadowLayer.path = UIBezierPath(roundedRect: self.bounds, cornerRadius: self.cornerRadius).cgPath
        shadowLayer.fillColor = self.backgroundColor?.cgColor
        shadowLayer.shadowPath = shadowLayer.path
        
//        shadowLayer.masksToBounds = false
        shadowLayer.shadowColor = color.cgColor
        shadowLayer.shadowOpacity = 1
        shadowLayer.shadowOffset = offset
        shadowLayer.shadowRadius = 10
//        shadowLayer.shouldRasterize = true

        return shadowLayer
    }

I don't know if either change is essential. But that's how it worked for me :)

Upvotes: 1

Hello below code will help you, I got exact result what you want in button shadow

just replace some function with my code,

Your code:

override func layoutSubviews() {

    super.layoutSubviews()
    addDropShadow()
}

Replace it with my code:

 override func layoutSubviews() {
        super.layoutSubviews()
        addDropShadow(color: UIColor.red, offset: CGSize(width: -6, height: -6), btnLayer: self.layer)
        addDropShadow(color: UIColor.blue, offset: CGSize(width: 6, height: 6), btnLayer: self.layer)
    }

Your code:

 private func addDropShadow() {
        let topLayer = createShadowLayer(color: Colours.shadowWhite, offset: CGSize(width: -6, height: -6))
        let bottomLayer = createShadowLayer(color: Colours.shadowBlack, offset: CGSize(width: 6, height: 6))

    layer.addSublayer(topLayer)
    layer.addSublayer(bottomLayer)
}

private func createShadowLayer(color: UIColor, offset: CGSize) -> CALayer {
    let shadowLayer = CALayer()
    shadowLayer.masksToBounds = false
    shadowLayer.shadowColor = color.cgColor
    shadowLayer.shadowOpacity = 1
    shadowLayer.shadowOffset = offset
    shadowLayer.shadowRadius = 10
    shadowLayer.shouldRasterize = true
    shadowLayer.shadowPath = UIBezierPath(roundedRect: self.bounds, cornerRadius: 10).cgPath

    return shadowLayer
}

Replace it with below code:

 private func addDropShadow(color: UIColor, offset: CGSize, btnLayer : CALayer)
    {

        btnLayer.masksToBounds = false
        btnLayer.shadowColor = color.cgColor
        btnLayer.shadowOpacity = 1
        btnLayer.shadowOffset = offset
        btnLayer.shadowRadius = 10

    }

no need to you private func createShadowLayer(color: UIColor, offset: CGSize) -> CALayer

you can remove that function.

and make sure your button type is custom

Upvotes: 0

Related Questions