Last active
July 7, 2023 13:05
-
-
Save pilot34/d8b2241f8d59526703ea758572e8b102 to your computer and use it in GitHub Desktop.
Dynamic intrinsicContentSize example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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