|
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 ?
|
|
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 🥵
|
|
I would toss out the autoresizing mask and just pin it with Autolayout to all sides..
|
|
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 ....
|
|
Yes, but you have to also pin the backgroundMaskedView to edges of the stack view
|
|
Also for a good measure, after pinning the view, call setNeedsLayout so it is forced to re-draw
|
|
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!
|