UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: Adding a gradient to a stackview

Forums > Swift

I know stackviews are not rendered, so to have a backgroundcolor, we have to insert a background view and give that a color to our liking. However, I want to have a gradient, but that just doesn't do anything:

extension UIStackView {
    ///Adds a background view to the stackview with the desired color and applies some corner radius
    func addBackground(_ color: UIColor, cornerRadius: CGFloat = 10) {
        let backgroundView = UIView(frame: bounds)
        backgroundView.backgroundColor = color
        backgroundView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        insertSubview(backgroundView, at: 0)
        backgroundView.layer.cornerRadius = cornerRadius
    }

    ///Adds a background view to the stackview with the desired color gradiant and applies some corner radius
    func addBackgroundGradiant(_ color1: UIColor, color2: UIColor, cornerRadius: CGFloat = 10) {
        let backgroundView = UIView(frame: bounds)
        backgroundView.backgroundColor = .clear
        backgroundView.autoresizingMask = [.flexibleWidth, .flexibleHeight]

        let gradientLayer = CAGradientLayer()
        gradientLayer.frame = backgroundView.bounds
        gradientLayer.colors = [UIColor.yellow.cgColor, UIColor.blue.cgColor]
        backgroundView.layer.insertSublayer(gradientLayer, at: 0)

        backgroundView.layer.cornerRadius = cornerRadius

        insertSubview(backgroundView, at: 0)
    }
}

First methods works fine, second method doesn't show any colors at all. What am I missing?

EDIT: Somehow the frame is not set correctly. Still figuring out how to do that other than I do above ... Bounds is in both methods (0,0,0,0). Why does the second method not work ?

2      

I changed my code so that it matches Paul's example of a masked gradient layer

    ///Adds a background view to the stackview with the desired color gradiant
    func addBackgroundGradiant(_ color1: UIColor, color2: UIColor, cornerRadius: CGFloat = 10) {
        let backgroundMaskedView = UIView(frame: bounds)
        backgroundMaskedView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        backgroundMaskedView.backgroundColor = .systemPurple

        let gradientMaskLayer = CAGradientLayer()
        gradientMaskLayer.frame = backgroundMaskedView.bounds
        gradientMaskLayer.colors = [UIColor.clear.cgColor, UIColor.white.cgColor, UIColor.white.cgColor, UIColor.clear.cgColor]
        gradientMaskLayer.locations = [0, 0.2, 0.8, 1]

        backgroundMaskedView.layer.mask = gradientMaskLayer
        insertSubview(backgroundMaskedView, at: 0)
    }

The gradient (layer) doesn't show. Only when I set the frame hard coded to some value like (0,0,200,200). I am calling the method from a custom cell class. @twostraws I am breaking my head here 🥵

2      

I would toss out the autoresizing mask and just pin it with Autolayout to all sides..

2      

That's worth a try. But what I don't get is that if I do

backgroundMaskedView.backgroundColor = UIColor.systemPurple

It just works ??

I call the method from my custom cell class:

class NormalProjectCell: UICollectionViewCell, SelfConfiguringProjectCell {
    //MARK: - Properties
    (...)

    //MARK: - Init
    override init(frame: CGRect) {
        super.init(frame: frame)

        let seperator = UIView(frame: .zero)
        seperator.translatesAutoresizingMaskIntoConstraints = false
        seperator.backgroundColor = .systemOrange

        let stackView = UIStackView(arrangedSubviews: [seperator, titleLabel, lastEditedLabel, imageView])
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.axis = .vertical
        stackView.distribution = .fillProportionally
        stackView.spacing = 5
        stackView.setCustomSpacing(10, after: lastEditedLabel)
//        stackView.addBackground(.purple, cornerRadius: 25)
        contentView.addSubview(stackView)

        NSLayoutConstraint.activate([
            seperator.heightAnchor.constraint(equalToConstant: 1),

            titleLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: 20),

            stackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
            stackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
            stackView.topAnchor.constraint(equalTo: contentView.topAnchor),
            stackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
        ])

        stackView.addBackgroundGradiant(UIColor.systemPurple, color2: UIColor.systemRed)
    }

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

    //MARK: - Configure
    func configure(with project: ProjectsController.Project) {
    (...)
    }
}

As you can see the stackView is set to top, bottom, leading and trailing ....

2      

Yes, but you have to also pin the backgroundMaskedView to edges of the stack view

2      

Also for a good measure, after pinning the view, call setNeedsLayout so it is forced to re-draw

2      

I just put the whole method code directly into my custom cell class. Without adjusting anything else. And it works!

@https://www.hackingwithswift.com/users/nemecek-filip I tried that too in several places to no avail ...

EDIT To help others in the future, it was a matter of when things get drawn. Besides that autoresizing masks doesn't work for layers! A really helpful article on the matter can be found here.

And it has a nice golden rule: add subviews or sublayers in some early one-time method, like a view’s init or didMoveToSuperview, or a view controller’s viewDidLoad. But do layout on subviews or sublayers in a layout method!

2      

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.