Skip to content

Instantly share code, notes, and snippets.

@pilot34
Last active July 7, 2023 13:05
Show Gist options
  • Save pilot34/d8b2241f8d59526703ea758572e8b102 to your computer and use it in GitHub Desktop.
Save pilot34/d8b2241f8d59526703ea758572e8b102 to your computer and use it in GitHub Desktop.
Dynamic intrinsicContentSize example
//
// ViewController.swift
// ConstantArea
//
// Created by Gleb Tarasov on 24.05.2020.
// Copyright © 2020 Gleb Tarasov. All rights reserved.
//
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let view1 = ConstantAreaView()
view1.translatesAutoresizingMaskIntoConstraints = false
view1.backgroundColor = .green
let container1 = UIView()
container1.translatesAutoresizingMaskIntoConstraints = false
container1.addSubview(view1)
self.view.addSubview(container1)
let view2 = ConstantAreaLabel()
view2.translatesAutoresizingMaskIntoConstraints = false
view2.backgroundColor = .red
let container2 = UIView()
container2.translatesAutoresizingMaskIntoConstraints = false
container2.addSubview(view2)
self.view.addSubview(container2)
NSLayoutConstraint.activate([
container1.leadingAnchor.constraint(equalTo: view1.leadingAnchor),
container1.trailingAnchor.constraint(equalTo: view1.trailingAnchor),
container1.topAnchor.constraint(equalTo: view1.topAnchor),
container1.bottomAnchor.constraint(equalTo: view1.bottomAnchor),
container1.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 50),
container1.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 50),
container2.leadingAnchor.constraint(equalTo: view2.leadingAnchor),
container2.trailingAnchor.constraint(equalTo: view2.trailingAnchor),
container2.topAnchor.constraint(equalTo: view2.topAnchor),
container2.bottomAnchor.constraint(equalTo: view2.bottomAnchor),
container2.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 250),
container2.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 50),
])
debugPrint("view systemLayoutSize width=500", container1.systemLayoutSizeFitting(CGSize(width: 500, height: CGFloat.greatestFiniteMagnitude), withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel))
debugPrint("view systemLayoutSize width=200", container1.systemLayoutSizeFitting(CGSize(width: 200, height: CGFloat.greatestFiniteMagnitude), withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel))
debugPrint("label systemLayoutSize width=500", container2.systemLayoutSizeFitting(CGSize(width: 500, height: CGFloat.greatestFiniteMagnitude), withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel))
debugPrint("label systemLayoutSize width=200", container2.systemLayoutSizeFitting(CGSize(width: 200, height: CGFloat.greatestFiniteMagnitude), withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel))
let widths = [
container1.widthAnchor.constraint(equalToConstant: 500),
container2.widthAnchor.constraint(equalToConstant: 500),
]
NSLayoutConstraint.activate(widths)
self.view.layoutIfNeeded()
debugPrint("view realSize width=500", container1.bounds.size)
debugPrint("label realSize width=500", container2.bounds.size)
widths[0].constant = 200
widths[1].constant = 200
self.view.layoutIfNeeded()
debugPrint("view width=200 real size", container1.bounds.size)
debugPrint("label width=200 real size", container2.bounds.size)
}
}
class ConstantAreaView: UIView {
init() {
super.init(frame: .zero)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private var preferredMaxLayoutWidth: CGFloat? {
didSet {
invalidateIntrinsicContentSize()
setNeedsLayout()
}
}
override var intrinsicContentSize: CGSize {
return calculateSize(width: preferredMaxLayoutWidth)
}
override func layoutSubviews() {
let width = bounds.size.width
if width == UIView.layoutFittingExpandedSize.width {
preferredMaxLayoutWidth = calculateSize(width: nil).width
} else if preferredMaxLayoutWidth != bounds.size.width {
preferredMaxLayoutWidth = bounds.size.width
} else {
// manually layout subviews here
super.layoutSubviews()
}
}
}
class ConstantAreaLabel: UILabel {
init() {
super.init(frame: .zero)
numberOfLines = 0
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(_ rect: CGRect) {
// do nothing, we are not a label actually
}
override func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect {
let resultSize = calculateSize(width: bounds.size.width)
return CGRect(origin: .zero, size: resultSize)
}
override func layoutSubviews() {
// layout subviews manually here
super.layoutSubviews()
}
}
func calculateSize(width: CGFloat?) -> CGSize {
let area: CGFloat = 10000
let defaultWidth: CGFloat = 100
let width = width ?? defaultWidth
if width <= 0 {
return .zero
}
return CGSize(width: width, height: area / width)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment