class CustomTableViewCell: UITableViewCell {
let nameLbl: UILabel = UILabel()
let profileBtn: UIButton = UIButton()
let aboutLbl: UILabel = UILabel()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(profileBtn)
contentView.addSubview(nameLbl)
contentView.addSubview(aboutLbl)
nameLbl.translatesAutoresizingMaskIntoConstraints = false
profileBtn.translatesAutoresizingMaskIntoConstraints = false
aboutLbl.translatesAutoresizingMaskIntoConstraints = false
profileBtn.backgroundColor = UIColor.red
nameLbl.font = UIFont(name: "Arial", size: 16)
aboutLbl.font = UIFont(name: "Arial", size: 16)
profileBtn.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
profileBtn.leftAnchor.constraint(equalTo: leftAnchor, constant: 20).isActive = true
profileBtn.widthAnchor.constraint(equalToConstant: 40).isActive = true
profileBtn.heightAnchor.constraint(equalToConstant: 40).isActive = true
self.profileBtn.layer.masksToBounds = true
self.profileBtn.layer.cornerRadius = CGFloat(roundf(Float(self.profileBtn.frame.size.width/2.0)))
nameLbl.topAnchor.constraint(equalTo: topAnchor, constant: 30).isActive = true
nameLbl.leftAnchor.constraint(equalTo: leftAnchor, constant: 70).isActive = true
nameLbl.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20).isActive = true
aboutLbl.topAnchor.constraint(equalTo: nameLbl.bottomAnchor, constant: 10).isActive = true
aboutLbl.leftAnchor.constraint(equalTo: leftAnchor, constant: 70).isActive = true
aboutLbl.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
i want the profile button inside the cell to have a round design.but ebven setting the corener radius and marskstobounds to true i am getting a square button. what am i doing wrong any help is apreciated. thanks in advance.
You are calculating the corner radius when the profile button hasn't been laid out yet. This means the width of the profile button will be zero rendering the corner radius the same. Move the line that you set the corner radius to an overriding method of layoutSubviews – this will ensure the views and subsequent sizes have been laid out in order for you to set the appropriate corner radius.
override func layoutSubviews() {
super.layoutSubviews()
profileBtn.layer.cornerRadius = profileBtn.frame.width / 2
}
Here is my solution:
override func layoutSubviews() {
super.layoutSubviews()
self.makeItCircle()
}
func makeItCircle() {
self.yourbutton.layer.masksToBounds = true
self.yourbutton.layer.cornerRadius = CGFloat(roundf(Float(self.yourbutton.frame.size.width/2.0)))
}
self.imageView.layer.masksToBounds = true //- in main
When you initialise the cell, the button does not have any frame. So self.profileBtn.layer.cornerRadius = CGFloat(roundf(Float(self.profileBtn.frame.size.width/2.0))) results in cornerRadius to be 0.
Since you are giving 40 constant width and height to the button, you can simply do this:
self.profileBtn.layer.cornerRadius = 20.0
Also make sure to set the button to clip the bounds:
self.profileBtn.clipsToBounds = true
Related
My project doesn't use Storyboards since it's using CleanSwift architecture.
Every views are built programmatically. Here's my table cell class.
class LiveScoreCell: UITableViewCell {
var data: LiveScores.Data? {
didSet {
leagueLogo.setImage(data?.leagueLogo)
}
}
var container: UIView = {
let view = UIView()
view.backgroundColor = .white
view.layer.cornerRadius = 10
view.layer.shadowColor = UIColor.black.cgColor
view.layer.shadowOffset = .zero
view.layer.shadowOpacity = 0.6
view.layer.shadowRadius = 10
view.layer.shadowPath = UIBezierPath(rect: view.bounds).cgPath
view.layer.borderWidth = 1
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
var leagueLogo: UIImageView = {
let imgView = UIImageView()
imgView.translatesAutoresizingMaskIntoConstraints = false
return imgView
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
selectionStyle = .none
setupViews()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
selectionStyle = .none
setupViews()
}
override func prepareForReuse() {
super.prepareForReuse()
}
func setupViews() {
addSubview(container)
container.topAnchor.constraint(equalTo: self.topAnchor, constant: 8).isActive = true
container.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -8).isActive = true
container.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 8).isActive = true
container.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -8).isActive = true
addSubview(leagueLogo)
leagueLogo.topAnchor.constraint(equalTo: container.topAnchor, constant: 8).isActive = true
leagueLogo.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 8).isActive = true
leagueLogo.widthAnchor.constraint(equalToConstant: 26).isActive = true
leagueLogo.heightAnchor.constraint(equalToConstant: 26).isActive = true
}
}
And the result is ..
Only border involves.. Any idea why is this happening?
As of this line
view.layer.shadowPath = UIBezierPath(rect: view.bounds).cgPath
runs when bounds is zero so make it inside
override func layoutSubviews() {
super.layoutSubviews()
container.layer.shadowPath = UIBezierPath(rect: container.bounds).cgPath
}
I have a simple UITableViewCell subclass in which I have a titleLabel property (the cell has more views, but for the sake of showing the issue, I will only do one label as it also breaks).
Here is my label code:
self.titleLabel = UILabel(frame: .zero)
self.titleLabel.numberOfLines = 0
self.titleLabel.font = UIFont.preferredFont(forTextStyle: .headline)
self.titleLabel.textColor = UIColor.white
self.titleLabel.adjustsFontSizeToFitWidth = false
self.titleLabel.textAlignment = .left
self.titleLabel.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(self.titleLabel)
self.titleLabel.topAnchor.constraint(equalTo: self.artworkImageView.topAnchor).isActive = true
self.titleLabel.leftAnchor.constraint(equalTo: self.artworkImageView.rightAnchor, constant: 10.0).isActive = true
self.titleLabel.rightAnchor.constraint(equalTo: self.contentView.rightAnchor, constant: -10.0).isActive = true
self.titleLabel.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor).isActive = true
I also set my UITableView up like this:
self.tableView.rowHeight = UITableView.automaticDimension
self.tableView.estimatedRowHeight = 50.0
However it keeps breaking constraints with an error like this:
"<NSLayoutConstraint:0x28211ce10 'UIView-Encapsulated-Layout-Height' UITableViewCellContentView:0x10859a4f0.height == 4.33333 (active)>"
There are more constraints, however this one says that my cell content view is only 4.3 of height, however I want it to grow as the label grows.
I also tried setting contentHuggingPriorities and the priority of the bottom anchor. I also compared it to code online or IB constraints I saw online and they all set 4 constraints: top, left, bottom, right.
I also tried leading and trailing instead of left and right - same result.
Any help appreciated
Here is my full AlbumTableViewCell:
class AlbumTableViewCell: UITableViewCell {
public private(set) var artworkImageView: UIImageView
public private(set) var titleLabel: UILabel
public private(set) var albumInfoLabel: UILabel
public private(set) var artistNameLabel: UILabel
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
self.artworkImageView = UIImageView(frame: .zero)
self.titleLabel = UILabel(frame: .zero)
self.albumInfoLabel = UILabel(frame: .zero)
self.artistNameLabel = UILabel(frame: .zero)
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.tintColor = UIColor.white
self.backgroundColor = UIColor.clear
self.contentView.backgroundColor = UIColor.barTintColor
self.contentView.layer.masksToBounds = false
self.contentView.layer.cornerRadius = 10.0
self.artworkImageView.layer.cornerRadius = 10.0
self.artworkImageView.layer.masksToBounds = true
self.artworkImageView.contentMode = .scaleAspectFit
self.artworkImageView.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(self.artworkImageView)
// image view
self.artworkImageView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 5).isActive = true
self.artworkImageView.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: 5).isActive = true
self.artworkImageView.widthAnchor.constraint(equalToConstant: 80).isActive = true
self.artworkImageView.heightAnchor.constraint(equalToConstant: 80).isActive = true
self.titleLabel = UILabel(frame: .zero)
self.titleLabel.numberOfLines = 2
self.titleLabel.font = UIFont.preferredFont(forTextStyle: .headline)
self.titleLabel.textColor = UIColor.white
self.titleLabel.adjustsFontSizeToFitWidth = false
self.titleLabel.textAlignment = .left
self.titleLabel.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(self.titleLabel)
// title
self.titleLabel.leadingAnchor.constraint(equalTo: self.artworkImageView.trailingAnchor, constant: 5.0).isActive = true
self.titleLabel.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: 5.0).isActive = true
self.titleLabel.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -5.0).isActive = true
self.titleLabel.heightAnchor.constraint(equalToConstant: 35).isActive = true
self.albumInfoLabel.numberOfLines = 1
self.albumInfoLabel.font = UIFont.preferredFont(forTextStyle: .subheadline)
self.albumInfoLabel.textColor = UIColor.lightGray
self.albumInfoLabel.adjustsFontSizeToFitWidth = true
self.albumInfoLabel.textAlignment = .left
self.albumInfoLabel.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(self.albumInfoLabel)
// albumInfoLabel
self.albumInfoLabel.topAnchor.constraint(equalTo: self.titleLabel.bottomAnchor, constant: 5.0).isActive = true
self.albumInfoLabel.leadingAnchor.constraint(equalTo: self.titleLabel.leadingAnchor).isActive = true
self.albumInfoLabel.trailingAnchor.constraint(equalTo: self.titleLabel.trailingAnchor).isActive = true
self.albumInfoLabel.heightAnchor.constraint(equalToConstant: 35).isActive = true
self.artistNameLabel = UILabel(frame: .zero)
self.artistNameLabel.numberOfLines = 1
self.artistNameLabel.font = UIFont.preferredFont(forTextStyle: .subheadline)
self.artistNameLabel.textColor = UIColor.lightGray
self.artistNameLabel.adjustsFontSizeToFitWidth = true
self.artistNameLabel.textAlignment = .left
self.artistNameLabel.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(self.artistNameLabel)
// albumInfoLabel
self.artistNameLabel.topAnchor.constraint(equalTo: self.albumInfoLabel.bottomAnchor, constant: 5.0).isActive = true
self.artistNameLabel.leadingAnchor.constraint(equalTo: self.albumInfoLabel.leadingAnchor).isActive = true
self.artistNameLabel.trailingAnchor.constraint(equalTo: self.albumInfoLabel.trailingAnchor).isActive = true
self.artistNameLabel.heightAnchor.constraint(equalToConstant: 35).isActive = true
let selectedView: UIView = UIView(frame: .zero)
selectedView.backgroundColor = UIColor.gray
selectedView.layer.cornerRadius = 10.0
selectedView.layer.masksToBounds = false
self.selectedBackgroundView = selectedView
}
override func layoutSubviews() {
super.layoutSubviews()
let contentViewFrame = self.contentView.frame
let insetContentViewFrame = contentViewFrame.inset(by: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10))
self.contentView.frame = insetContentViewFrame
self.selectedBackgroundView?.frame = insetContentViewFrame
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
This code does not crash anymore but the cell does not autoresize (see image).. The light gray area is the content view
this code does not break any constrains anymore, but the cell also does not calculate the hight automatically. Here is my table view controller:
self.tableView.register(AlbumTableViewCell.self, forCellReuseIdentifier: "AlbumCell")
self.tableView.separatorStyle = .none
self.tableView.tableFooterView = UIView(frame: .zero)
self.tableView.rowHeight = UITableView.automaticDimension
self.tableView.estimatedRowHeight = 50.0
var titleLabel = UILabel()
contentView.addSubview(titleLabel)
titleLabel.textColor = UIColor(red:0.32, green:0.17, blue:0.12, alpha:1.0)
titleLabel.font = UIFont.boldSystemFont(ofSize: 16.0)
titleLabel.translatesAutoresizingMaskIntoConstraints = false
titleLabel.topAnchor.constraint(equalTo: marginGuide.topAnchor).isActive = true
titleLabel.trailingAnchor.constraint(equalTo: marginGuide.trailingAnchor, constant: 8).isActive = true
titleLabel.bottomAnchor.constraint(equalTo: marginGuide.bottomAnchor).isActive = true
titleLabel.leadingAnchor.constraint(equalTo: marginGuide.leadingAnchor, constant: 8).isActive = true
Try this.
To be honest i don't know exactly what's your issue but i know for sure that you have a bad time with cell constraint and you want a dynamic cell .
So let's say you have a cell with 4 views artWrokImageView , artNameLabel , artDescriptionLabel and the artistNameLabel
First you need to make sure these views most constraint from top and bottom the table cell , So when you call self.tableView.rowHeight = UITableView.automaticDimension it knows how to dynamically expand .
Second you need to tell the table to expand when ever view did appear
This is demo for the 4 views above .
Table View Controller :
class YourTableViewController : UITableViewController {
let customTableCellID = "customTableCellID";
override func viewDidLoad() {
super.viewDidLoad();
setupTable();
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.tableView.estimatedRowHeight = 50;
self.tableView.rowHeight = UITableView.automaticDimension;
}
fileprivate func setupTable() {
tableView.register(YourCustomTableCell.self, forCellReuseIdentifier: customTableCellID);
}
}
extension YourTableViewController {
override func numberOfSections(in tableView: UITableView) -> Int {
return 1;
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1;
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: customTableCellID, for: indexPath) as! YourCustomTableCell
cell.artistNameLabel.text = "the real art";
cell.artworkImageView.image = UIImage(named: "mazen");
cell.artDescriptionLabel.text = "long long long long long long long long long long long long long long long long long long long long long long long long long description";
cell.artNameLabel.text = "someting"
return cell
}
}
Cell :
class YourCustomTableCell : UITableViewCell {
var artworkImageView : UIImageView = {
let imageView = UIImageView();
imageView.translatesAutoresizingMaskIntoConstraints = false;
return imageView;
}()
var artNameLabel : UILabel = {
let label = UILabel();
label.font = UIFont.boldSystemFont(ofSize: 20);
label.translatesAutoresizingMaskIntoConstraints = false;
return label
}()
var artDescriptionLabel : UILabel = {
let label = UILabel();
label.textColor = .darkGray;
label.numberOfLines = 0;
label.translatesAutoresizingMaskIntoConstraints = false;
return label;
}()
var artistNameLabel : UILabel = {
let label = UILabel();
label.textColor = .blue;
label.translatesAutoresizingMaskIntoConstraints = false;
return label;
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier);
setupCell();
}
fileprivate func setupCell() {
// add views
contentView.addSubview(artworkImageView);
contentView.addSubview(artNameLabel);
contentView.addSubview(artDescriptionLabel);
contentView.addSubview(artistNameLabel);
// layout views
// image view
artworkImageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 5).isActive = true;
artworkImageView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 5).isActive = true;
artworkImageView.widthAnchor.constraint(equalToConstant: 80).isActive = true;
artworkImageView.heightAnchor.constraint(equalToConstant: 80).isActive = true;
// art name
artNameLabel.leadingAnchor.constraint(equalTo: artworkImageView.trailingAnchor, constant: 5).isActive = true;
artNameLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 5).isActive = true;
artNameLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -5).isActive = true;
artNameLabel.heightAnchor.constraint(equalToConstant: 35).isActive = true;
// descripion
artDescriptionLabel.leadingAnchor.constraint(equalTo: artworkImageView.trailingAnchor, constant: 5).isActive = true;
artDescriptionLabel.topAnchor.constraint(equalTo: artNameLabel.bottomAnchor, constant: 5).isActive = true;
artDescriptionLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -5).isActive = true;
// in art description label don't set the height anchors so it can expand
// artist name
artistNameLabel.leadingAnchor.constraint(equalTo: artworkImageView.trailingAnchor, constant: 5).isActive = true;
artistNameLabel.topAnchor.constraint(equalTo: artDescriptionLabel.bottomAnchor, constant: 5).isActive = true;
artistNameLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -5).isActive = true;
artistNameLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -5).isActive = true; // this constraint is requierd for dynamic cell
}
required init?(coder aDecoder: NSCoder) {
fatalError()
}
}
And if this answer not in your case please tell me .
Your tableviewcells don't know what their height is suppose to be. Which is fine.
You just have to give enough constraints so that it can figure it out. You're not doing that!
The major issue I currently see is that the artworkImageView is not constrained to top and bottom. Every vertical axiom of views needs to be constrained top to bottom.
Your first vertical axiom is just the image. It doesn't have a bottom constraint. Add that. So the tableviewcell knows how much it needs to resize itself. I strongly recommend you to see this moment of WWDC.
Also earlier in the same video at this moment it strongly recommend that you just dump your views in multiple stackviews and organize it that way. So that's also an alternative.
PS:
don't dump self. It just increases the line width with no added benefit.
Move all your non-layout related setup of your labels/images to their own instantiation. e.g.
lazy label : UILabel = {
let label = UILabel()
label.text = "John"
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
No need to mention frame : .zero. Just UILabel() implies the frame is zero.
It's always best to start your UI small then keep adding more elements to it. That way debugging your layout becomes easier/smaller.
I have a prototype cell for a collection view and am trying to make the edges rounded, but I can't figure out how to use self.layer.cornerRadius = 3.0 and make it work. Could anyone tell me what I'm doing wrong?
import UIKit
final class TagCell: UICollectionViewCell {
let textLabel: UILabel
override init(frame: CGRect) {
self.textLabel = UILabel(frame: .zero)
self.textLabel.setFont(14)
self.textLabel.translatesAutoresizingMaskIntoConstraints = false
self.textLabel.textAlignment = .center
self.textLabel.backgroundColor = .red
self.textLabel.layer.cornerRadius = 2.0
super.init(frame: frame)
self.contentView.layer.cornerRadius = 2.0
self.contentView.clipsToBounds = true
self.contentView.addSubview(textLabel)
NSLayoutConstraint.activate([
self.textLabel.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: 16),
self.textLabel.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: -16),
self.textLabel.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 16),
self.textLabel.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -16),
])
}
required init?(coder decoder: NSCoder) {
fatalError()
}
}
it's better to create a subView inside the contentView and apply the corner to it
self.contentView.layer.cornerRadius = 2.0
self.contentView.clipsToBounds = true
I have a view controller with XIB, with a view (contentView) inside. This view contains some buttons.
The content view has round corners and clips to bounds, but it doesn't respect the clipping rect. I set the corner radius and the clipsToBounds in the viewDidLoad of the view controller.
Here you can see the reveal screenshot that shows that the view is composed in the correct way, but on simulator and device clipping bounds are not respected.
Anybody can please help me to understand what happen.
The app is targeted to iOS 10 and 11, and both have the same issue.
I found a solution, I move the clipsToBound in the viewDidLayoutSubviews instead viewDidLoad and now works
override func viewDidLoad() {
super.viewDidLoad()
contentView.layer.cornerRadius = Dimensions.CornerRaius
contentView.dropShadow()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
contentView.clipsToBounds = true
}
I defined my view (UIView in my case) like that:
fileprivate let backView: UIView = {
let view = UIView()
view.clipsToBounds = true
view.layer.masksToBounds = false
view.layer.cornerRadius = 10
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
The image:
fileprivate let imgView: UIImageView = {
let iv = UIImageView()
iv.translatesAutoresizingMaskIntoConstraints = false
return iv
}()
In my case I defined these elements in a custom table view cell:
class customCell: UITableViewCell {
Although I set "clipsToBounds = true" in the definition of background view, not clip the image.
But, if I set "clipsToBounds = true" later, it clips the image.
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
backView.addSubview(imgView)
contentView.addSubview(backView)
imgView.topAnchor.constraint(equalTo: backView.topAnchor, constant: 0).isActive = true
imgView.leadingAnchor.constraint(equalTo: backView.leadingAnchor, constant: 0).isActive = true
imgView.trailingAnchor.constraint(equalTo: backView.trailingAnchor, constant: 0).isActive = true
imgView.heightAnchor.constraint(equalTo: imgView.widthAnchor, multiplier: 1/4).isActive = true
backView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 0).isActive = true
backView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 15).isActive = true
backView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -15).isActive = true
backView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 0).isActive = true
And inside "init" method:
backView.clipsToBounds = true
I have the following UIView:
It is a UIView which contains three subviews. A regular UILabel (Hello World) at the top, a custom UIViewController (CategoryList) which contains a CollectionView with buttons (alpha,beta, ...) and another custom UIViewController with just a label (SALUT).
I do auto-layout programmatically and position SALUT (var sCtrl) below the CategoryList (var catList) with
sCtrl.view.topAnchor.constraint(equalTo: catList.view.bottomAnchor).isActive = true
This results in the picture above, where SALUT is not positioned below the category list as I would like it to be. I sort of understand why since when I set the constraint the buttons are not yet laid out properly in the CollectionView and thus the bottom anchor of the catList is not set.
In the CategoryList:UIVIewController I have the following in order to get the collection view to get the correct height.
override public func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
heightConstraint = collectionView.heightAnchor.constraint(equalToConstant: collectionView.collectionViewLayout.collectionViewContentSize.height)
self.view.addConstraint(heightConstraint)
}
This works but since viewDidLayoutSubviews() is called after the constraint is set on SALUT the SALUT position is wrong. How can I get it right in an easy way? (I guess I could make a controller for my main view and check there when subviews are laid out and then update subview positions but this seems overly complicated to me).
The full code for the main view is below so you can see the layout positioning code. If needed I can also provide the subviews code but I suppose it shouldn't be needed since they should be considered black boxes...
class MyView: UIView {
let label = UILabel()
var sCtrl : SubController
var catList : CategoryList
var topConstraint = NSLayoutConstraint()
override init(frame: CGRect) {
sCtrl = SubController()
catList = CategoryList()
super.init(frame: frame)
setup()
}
private func setup() {
self.backgroundColor = UIColor.green
label.translatesAutoresizingMaskIntoConstraints = false
label.backgroundColor = UIColor.yellow
label.text = "Hello world"
label.textAlignment = .center
self.addSubview(label)
catList.view.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(catList.view)
sCtrl.view.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(sCtrl.view)
let margins = self.layoutMarginsGuide
label.leadingAnchor.constraint(equalTo: margins.leadingAnchor, constant: 0).isActive = true
label.trailingAnchor.constraint(equalTo: margins.trailingAnchor, constant: 0).isActive = true
label.topAnchor.constraint(equalTo: margins.topAnchor, constant: 0).isActive = true
label.heightAnchor.constraint(equalToConstant: 100.0).isActive=true
catList.view.leadingAnchor.constraint(equalTo: margins.leadingAnchor, constant: 0).isActive = true
catList.view.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 1.0).isActive = true
catList.view.widthAnchor.constraint(equalTo: margins.widthAnchor, multiplier: 1.0).isActive = true
catList.view.trailingAnchor.constraint(equalTo: margins.trailingAnchor, constant:0).isActive = true
sCtrl.view.topAnchor.constraint(equalTo: catList.view.bottomAnchor).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
let v = MyView(frame: CGRect(x: 0, y: 0, width: 400, height: 600))
Ok, I found the issue. I had missed to add the height constraint to the CategoryList's own view. Adding this it works just fine.
override public func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
heightConstraint = collectionView.heightAnchor.constraint(equalToConstant: collectionView.collectionViewLayout.collectionViewContentSize.height)
self.view.addConstraint(heightConstraint)
//THE MISSING LINE!!
self.view.heightAnchor.constraint(equalTo: self.collectionView.heightAnchor, constant: 0).isActive = true
}