// import UIKit class AutoSizingStringDrawer: UIView { @NSCopying var attributedText = NSAttributedString() { didSet { self.setNeedsDisplay() self.invalidateIntrinsicContentSize() } } override func draw(_ rect: CGRect) { self.attributedText.draw(with: rect, options: [.truncatesLastVisibleLine, .usesLineFragmentOrigin], context: nil) } override var intrinsicContentSize: CGSize { let measuredSize = self.attributedText.boundingRect( with: CGSize(width:self.bounds.width, height:10000), options: [.truncatesLastVisibleLine, .usesLineFragmentOrigin], context: nil).size print("Drawer intrinsicContentSize:", measuredSize, "bounds:", bounds.size) return CGSize(width: UIView.noIntrinsicMetric, height: measuredSize.height.rounded(.up) + 5) } var currentWidth: CGFloat = 0.0 override func layoutSubviews() { super.layoutSubviews() if currentWidth != bounds.width { currentWidth = bounds.width self.invalidateIntrinsicContentSize() } print("Drawer layoutSubviews bounds.size", bounds.size) } } class MyLabel: UILabel { override var intrinsicContentSize: CGSize { let sz = super.intrinsicContentSize print("MyLabel intrinsicContentSize:", sz, "bounds:", bounds.size) return sz } override func layoutSubviews() { super.layoutSubviews() print("MyLabel layoutSubviews bounds.size:", bounds.size) } } class StringDrawer: UIView { @NSCopying var attributedText = NSAttributedString() { didSet { self.setNeedsDisplay() self.invalidateIntrinsicContentSize() } } override func draw(_ rect: CGRect) { self.attributedText.draw(with: rect, options: [.truncatesLastVisibleLine, .usesLineFragmentOrigin], context: nil) } override var intrinsicContentSize: CGSize { let measuredSize = self.attributedText.boundingRect( with: CGSize(width:self.bounds.width, height:10000), options: [.truncatesLastVisibleLine, .usesLineFragmentOrigin], context: nil).size print("Drawer intrinsicContentSize:", measuredSize, "bounds:", bounds.size) return CGSize(width: UIView.noIntrinsicMetric, height: measuredSize.height.rounded(.up) + 5) } override func layoutSubviews() { super.layoutSubviews() print("Drawer layoutSubviews bounds.size", bounds.size) } } class TestViewController: UIViewController { let testDrawer: StringDrawer = StringDrawer() let testLabel: MyLabel = MyLabel() let testString = "enough text to cause word wrapping to test the intrinsic content size issue." override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .yellow [testDrawer, testLabel].forEach { v in v.translatesAutoresizingMaskIntoConstraints = false view.addSubview(v) } let g = view.safeAreaLayoutGuide NSLayoutConstraint.activate([ testDrawer.topAnchor.constraint(equalTo: g.topAnchor, constant: 100.0), testDrawer.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0), testDrawer.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0), testLabel.topAnchor.constraint(equalTo: g.topAnchor, constant: 200.0), testLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0), testLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0), ]) testDrawer.backgroundColor = .cyan testLabel.backgroundColor = .green testLabel.numberOfLines = 0 let drawerString = NSAttributedString(string: "Drawer: " + testString, attributes: [ .foregroundColor : UIColor.darkText, .font : UIFont(name: "Helvetica", size: 14)! ]) let labelString = NSAttributedString(string: "Label: " + testString, attributes: [ .foregroundColor : UIColor.darkText, .font : UIFont(name: "Helvetica", size: 14)! ]) testDrawer.attributedText = drawerString testLabel.attributedText = labelString } } /* Console output with iPhone 8 / 14.0 / Simulator Drawer intrinsicContentSize: (513.59765625, 16.1) bounds: (0.0, 0.0) MyLabel intrinsicContentSize: (65536.0, 16.5) bounds: (0.0, 0.0) MyLabel intrinsicContentSize: (65536.0, 16.5) bounds: (0.0, 0.0) MyLabel intrinsicContentSize: (335.0, 32.5) bounds: (0.0, 0.0) MyLabel intrinsicContentSize: (65536.0, 16.5) bounds: (0.0, 0.0) MyLabel intrinsicContentSize: (335.0, 32.5) bounds: (0.0, 0.0) MyLabel layoutSubviews bounds.size: (335.0, 32.5) MyLabel layoutSubviews bounds.size: (335.0, 32.5) Drawer layoutSubviews bounds.size (335.0, 22.0) */