The problem is, that we have view hierarchy with multiple levels of views that uses autoSizeThatFits function to calculate its size and the resulting size is wrong.
Here is the example of view hierarchy and code to reproduce this bug.
Hierarchy

Code
class GreenView: UIView {
var child = YellowView()
override func sizeThatFits(_ size: CGSize) -> CGSize {
let size = autoSizeThatFits(size, layoutClosure: layout)
return size
}
override func layoutSubviews() {
super.layoutSubviews()
layout()
}
func layout() {
child.pin.left().top().bottom().right().margin(10).sizeToFit(.width)
}
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() {
backgroundColor = .green
addSubview(child)
}
}
class YellowView: UIView {
var child = RedView()
override func sizeThatFits(_ size: CGSize) -> CGSize {
let size = autoSizeThatFits(size, layoutClosure: layout)
return size
}
override func layoutSubviews() {
super.layoutSubviews()
layout()
}
func layout() {
child.pin.left().top().bottom().right().margin(10).sizeToFit(.width)
}
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() {
backgroundColor = .yellow
addSubview(child)
}
}
class RedView: UIView {
let label = UILabel()
override func sizeThatFits(_ size: CGSize) -> CGSize {
let size = autoSizeThatFits(size, layoutClosure: layout)
return size
}
override func layoutSubviews() {
super.layoutSubviews()
layout()
}
func layout() {
label.pin.all().sizeToFit(.width)
}
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() {
backgroundColor = .red
addSubview(label)
label.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque dolor est, interdum vitae congue bibendum, semper quis quam. Fusce commodo varius pretium. Pellentesque feugiat lacus vitae sapien faucibus, non rutrum purus fringilla."
label.numberOfLines = 0
}
}
Just add GreenView to your example view and layout it like
greenView.pin.top().start().end().sizeToFit(.width)
The sizes of these views would be:
| View |
sizeThatFits(_ size:) {input} ; {output} |
Resulting size |
| GreenView |
{375, 0} ; {375, 60} |
{375, 60} |
| YellowView |
{355, 0} ; {20, 40} |
{355, 142} |
| RedView |
{-20, 0} ; {0, 20} |
{335, 122} |
| UILabel |
{0, 0} ; {1828, 20} |
{335, 122} |
The problem is, that we have view hierarchy with multiple levels of views that uses
autoSizeThatFitsfunction to calculate its size and the resulting size is wrong.Here is the example of view hierarchy and code to reproduce this bug.
Hierarchy
Code
Just add
GreenViewto your example view and layout it likegreenView.pin.top().start().end().sizeToFit(.width)The sizes of these views would be: