UIView clipsToBounds doesn't work - ios

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

Related

Async height change for UITableViewCell

In one of my projects, I need to change the height of UIImageView in UITableViewCell according to image size, but the problem is that sometimes I have to do this after the cell is already shown.
So, my current solution works like a charm if I know all the image sizes beforehand, but if I'm trying to calculate this with some delay – it's completely broken (especially with scrolling but it's broken even without it).
I made the example project to illustrate this. There is no async downloading, but I'm trying to dynamically change the height of UIImageView after some delay (1s). The height depends on UIImageView, so every next UIImageView should be slightly higher (10 pixels) than previous one. Also, I have a UILabel, constrained to UIImageView.
It looks like that (UIImageViews are the red ones)
If I'm trying to do this async, it looks like this, all the UILabels are really broken here.
and this is one after the scroll (async too):
What am I doing wrong here? I've read several threads about dynamic heights, but none of the solutions worked for me yet.
My code is fairly simple:
func addTableView() {
tableView = UITableView()
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.dataSource = self
tableView.delegate = self
tableView.separatorStyle = .none
tableView.estimatedRowHeight = 100
tableView.rowHeight = UITableView.automaticDimension
tableView.backgroundColor = .black
tableView.register(DynamicCell.self, forCellReuseIdentifier: "dynamicCell")
view.addSubview(tableView)
tableView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true
tableView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0).isActive = true
tableView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "dynamicCell", for: indexPath) as! DynamicCell
cell.message = messageArray[indexPath.row]
cell.backgroundColor = .clear
cell.selectionStyle = .none
cell.buildCell()
return cell
}
DynamicCell.swift (delegate is doing nothing right now):
var backView: UIView!
var label: UILabel!
var picView: UIImageView!
var message: DMessage?
var picViewHeight: NSLayoutConstraint!
var delegate: RefreshCellDelegate?
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
backView = UIView()
backView.translatesAutoresizingMaskIntoConstraints = false
backView.backgroundColor = .white
backView.clipsToBounds = true
backView.layer.cornerRadius = 8.0
self.addSubview(backView)
label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.textAlignment = .left
label.textColor = .black
label.numberOfLines = 0
backView.addSubview(label)
picView = UIImageView()
picView.translatesAutoresizingMaskIntoConstraints = false
picView.clipsToBounds = true
picView.backgroundColor = .red
backView.addSubview(picView)
addMainConstraints()
}
func addMainConstraints() {
backView.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 8).isActive = true
backView.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -32).isActive = true
backView.topAnchor.constraint(equalTo: self.topAnchor, constant: 4).isActive = true
backView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -4).isActive = true
picView.topAnchor.constraint(equalTo: backView.topAnchor, constant: 0).isActive = true
picView.leftAnchor.constraint(equalTo: backView.leftAnchor, constant: 0).isActive = true
picView.rightAnchor.constraint(equalTo: backView.rightAnchor, constant: 0).isActive = true
label.topAnchor.constraint(equalTo: picView.bottomAnchor, constant: 0).isActive = true
label.leftAnchor.constraint(equalTo: backView.leftAnchor, constant: 8).isActive = true
label.rightAnchor.constraint(equalTo: backView.rightAnchor, constant: -8).isActive = true
label.bottomAnchor.constraint(equalTo: backView.bottomAnchor, constant: -4).isActive = true
picViewHeight = NSLayoutConstraint(item: picView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 100)
picViewHeight.priority = UILayoutPriority(999)
picViewHeight.isActive = true
}
override func prepareForReuse() {
picViewHeight.constant = 0
//picViewHeight.constant = 0
}
func buildCell() {
guard let message = message else {return}
label.attributedText = NSAttributedString(string: message.text)
changeHeightWithDelay()
//changeHeightWithoutDelay()
}
func changeHeightWithoutDelay() {
if let nh = self.message?.imageHeight {
self.picViewHeight.constant = nh
self.delegate?.refreshCell(cell: self)
}
}
func changeHeightWithDelay() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
if let nh = self.message?.imageHeight {
self.picViewHeight.constant = nh
self.delegate?.refreshCell(cell: self)
}
}
}
putting this as an answer.
one thing I noticed, when you are playing around with cell, it's always better to use the contentView instead of directly using self. ie self.contentView.addSubview(). what does refreshcell function do? have you tried marking it as needsSetDisplay so in the next draw cycle it will be updated? have you tried calling layoutIfNeeded?
To explain a bit further, your view has already been 'rendered' the moment you want to change the height/width of your view you need to inform it that there's an update. this happens when you mark the view as setNeedsDisplay and in the next render cycle it will be updated
more info on apple's documentation here
You can use this method or the setNeedsDisplay(_:) to notify the system that your view’s contents need to be redrawn. This method makes a note of the request and returns immediately. The view is not actually redrawn until the next drawing cycle, at which point all invalidated views are updated.

how to get a round UIbutton in tableviewcell in swift?

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

Add fullscreen view as subview of view controller

I want to make a view1 that I can add as a subview to my view controller that covers the whole screen. Then inside view1 I want to place a 100x100 view2 in the center.
How can I do this with swift? (not storyboard). I want to create a stand alone uiview class, not just a variable inside the view controller.
I want to make view1 userInteractionDisabled.
As you want stand alone uiview class, for two views make two classes. Thus modulating the code better, as following:
class TypeOneView: UIView {
convenience init() {
self.init(frame: UIScreen.main.bounds)
isUserInteractionEnabled = false
// more ui customization
backgroundColor = UIColor.green
// add more customization if you want
}
}
class TypeTwoView: UIView {
convenience init(_ width: Double,_ height: Double) {
let fullScreenHeight = Double(UIScreen.main.bounds.height)
let fullScreenWidth = Double(UIScreen.main.bounds.width)
self.init(frame: CGRect(x: (fullScreenWidth/2) - (width/2), y: (fullScreenHeight/2) - (height/2), width: width, height: width))
// additional ui customization
backgroundColor = UIColor.red
// add more customization if you want
}
}
Then instantiate and add these views as subview in your target view controller class as:
let view1 = TypeOneView()
let view2 = TypeTwoView(100.0, 100.0)
view.addSubview(view1)
view.addSubview(view2)
view.bringSubview(toFront: view2)
result:
var view1:UIView!
var view2:UIView!
override func viewDidLoad() {
view1.translatesAutoresizingMaskIntoConstraints = false
view1.isUserInteractionEnabled = false
self.view.addSubview(view1)
view1.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0).isActive = true
view1.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: 0).isActive = true
view1.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 0).isActive = true
view1.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0).isActive = true
view2.translatesAutoresizingMaskIntoConstraints = false
self.view1.addSubview(view2)
view2.heightAnchor.constraint(equalToConstant: 100).isActive = true
view2.widthAnchor.constraint(equalToConstant: 100).isActive = true
view2.centerXAnchor.constraint(equalTo: self.view1.centerXAnchor).isActive = true
view2.centerYAnchor.constraint(equalTo: self.view1.centerYAnchor).isActive = true
}
Check out this. It would be something like this
class MyView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
addMySubviews()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
addMySubviews()
}
func addMySubviews() {
let view = UIView(frame: CGRect.zero)
view.translatesAutoresizingMaskIntoConstraints = false
addSubview(view)
leadingAnchor.constraintEqualToSystemSpacingAfter(view.leadingAnchor, multiplier: 0).isActive = true
topAnchor.constraintEqualToSystemSpacingBelow(view.topAnchor, multiplier: 0).isActive = true
trailingAnchor.constraintEqualToSystemSpacingAfter(view.trailingAnchor, multiplier: 0).isActive = true
bottomAnchor.constraintEqualToSystemSpacingBelow(view.bottomAnchor, multiplier: 0).isActive = true
let view100x100 = UIView(frame: CGRect.zero)
view100x100.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(view100x100)
view100x100.centerXAnchor.constraintEqualToSystemSpacingAfter(centerXAnchor, multiplier: 0).isActive = true
view100x100.centerYAnchor.constraintEqualToSystemSpacingBelow(centerYAnchor, multiplier: 0).isActive = true
view100x100.heightAnchor.constraint(equalToConstant: 100).isActive = true
view100x100.widthAnchor.constraint(equalToConstant: 100).isActive = true
}
}
Use as mentioned below:
let myView = MyView(frame: CGRect(x: 0, y: 0, width: 275, height: 600))
OR
let myView = MyView(frame: view.frame)
myView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(myView)
myView.leadingAnchor.constraintEqualToSystemSpacingAfter(view.leadingAnchor, multiplier: 0).isActive = true
myView.topAnchor.constraintEqualToSystemSpacingBelow(view.topAnchor, multiplier: 0).isActive = true
myView.trailingAnchor.constraintEqualToSystemSpacingAfter(view.trailingAnchor, multiplier: 0).isActive = true
myView.bottomAnchor.constraintEqualToSystemSpacingBelow(view.bottomAnchor, multiplier: 0).isActive = true

How to set constraint relationship to view, not subviews programmatically?

I am trying to setup a couple of views programmatically. On my main view I add two subviews, one anchored to the top and one to the bottom:
//Button View
view.addSubview(buttonsLabel)
buttonsLabel.translatesAutoresizingMaskIntoConstraints = false
buttonsLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
buttonsLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
buttonsLabel.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -20).isActive = true
buttonsLabel.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.5, constant: -20).isActive = true
//Calculator View
calcLabel.layer.cornerRadius = 25
view.addSubview(calcLabel)
calcLabel.translatesAutoresizingMaskIntoConstraints = false
calcLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
calcLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
calcLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 40).isActive = true
//calcLabel.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -20).isActive = true
calcLabel.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.5, constant: -40).isActive = true
This works fine, both views are 50% of the frame height (minus the constants) and both are shown (one at the top, one at the bottom). But when I try to add a third view, which is 75% of the frames height and which should be placed on top of the other two views, the layout is destroyed and everything is moved almost outside of the frame.
I am trying to anchor the third view to the bottom again:
thirdView.layer.cornerRadius = 25
view.addSubview(thirdView)
thirdView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
thirdView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
thirdView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
thirdView.heightAnchor.constraint(equalTo: view.heightAnchor,multiplier: 0.75).isActive = true
This is how everything should look like (left the two views, right the third view on top:
Am I doing the anchors and constraints right (or whats abetter way) and how to add the constraint for the third view, so that it is 75% of the frames height and placed like in the image on top of everything.
Your code looks good the problem is else where, check the view hierarchy in the debugger to see which constraint(s) failed, perhaps you forgot translatesAutoresizingMaskIntoConstraints as beyowulf commented. you should be using constants as well, this makes code much more maintainable.
here is my implementation:
import UIKit
class ViewController: UIViewController {
//MARK: - SubViews
let topHalfView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = UIColor.gray
return view
}()
let bottomHalfView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = UIColor.gray
return view
}()
let threeQuarterView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = UIColor.black
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//add, layout subviews with 9+ constraints
setupViews()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func setupViews() {
self.view.addSubview(topHalfView)
self.view.addSubview(bottomHalfView)
self.view.addSubview(threeQuarterView)
let guide = self.view.safeAreaLayoutGuide
let spacing:CGFloat = 12
let viewHeight = self.view.frame.height - spacing
topHalfView.topAnchor.constraint(equalTo: guide.topAnchor).isActive = true
topHalfView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: spacing).isActive = true
topHalfView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -spacing).isActive = true
topHalfView.heightAnchor.constraint(equalToConstant: viewHeight * 0.5).isActive = true
bottomHalfView.topAnchor.constraint(equalTo: topHalfView.bottomAnchor, constant: spacing).isActive = true
bottomHalfView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: spacing).isActive = true
bottomHalfView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -spacing).isActive = true
bottomHalfView.heightAnchor.constraint(equalToConstant: viewHeight * 0.5).isActive = true
threeQuarterView.bottomAnchor.constraint(equalTo: guide.bottomAnchor).isActive = true
threeQuarterView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: spacing).isActive = true
threeQuarterView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -spacing).isActive = true
threeQuarterView.heightAnchor.constraint(equalToConstant: self.view.frame.height * 0.75).isActive = true
}
}
The View hierarchy:

How to position a subView below a subView with dynamic height?

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
}

Resources