Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- extension String {
- func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
- let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
- let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
- return ceil(boundingBox.height)
- }
- func width(withConstrainedHeight height: CGFloat, font: UIFont) -> CGFloat {
- let constraintRect = CGSize(width: .greatestFiniteMagnitude, height: height)
- let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
- return ceil(boundingBox.width)
- }
- }
- class CommentCell: UICollectionViewCell {
- let profileImageView = UIImageView()
- let nameLabel = UILabel()
- let titleLabel = UILabel()
- let commentLabel = UILabel()
- var titleFont: UIFont = .systemFont(ofSize: 16.0)
- var commentFont: UIFont = .systemFont(ofSize: 16.0)
- override init(frame: CGRect) {
- super.init(frame: frame)
- commonInit()
- }
- required init?(coder: NSCoder) {
- super.init(coder: coder)
- commonInit()
- }
- func commonInit() -> Void {
- contentView.backgroundColor = UIColor(white: 0.95, alpha: 1.0)
- commentLabel.numberOfLines = 6
- [titleLabel, commentLabel].forEach { v in
- v.setContentHuggingPriority(.required, for: .vertical)
- v.backgroundColor = .yellow
- }
- [profileImageView, nameLabel, titleLabel, commentLabel].forEach { v in
- v.translatesAutoresizingMaskIntoConstraints = false
- contentView.addSubview(v)
- }
- profileImageView.backgroundColor = .red
- nameLabel.text = "Name Label"
- titleLabel.text = "Title Label"
- let g = contentView
- NSLayoutConstraint.activate([
- profileImageView.topAnchor.constraint(equalTo: g.topAnchor, constant: 8.0),
- profileImageView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 8.0),
- profileImageView.widthAnchor.constraint(equalToConstant: 80.0),
- profileImageView.heightAnchor.constraint(equalTo: profileImageView.widthAnchor),
- nameLabel.leadingAnchor.constraint(equalTo: profileImageView.trailingAnchor, constant: 8.0),
- nameLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -8.0),
- nameLabel.centerYAnchor.constraint(equalTo: profileImageView.centerYAnchor),
- titleLabel.topAnchor.constraint(equalTo: profileImageView.bottomAnchor, constant: 8.0),
- titleLabel.leadingAnchor.constraint(equalTo: profileImageView.leadingAnchor, constant: 0.0),
- titleLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -8.0),
- commentLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 8.0),
- commentLabel.leadingAnchor.constraint(equalTo: titleLabel.leadingAnchor, constant: 0.0),
- commentLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -8.0),
- commentLabel.bottomAnchor.constraint(lessThanOrEqualTo: g.bottomAnchor, constant: -8.0),
- ])
- }
- }
- class SampleViewController: UIViewController {
- var collectionView: UICollectionView!
- var collectionViewHeightConstraint: NSLayoutConstraint!
- var flowLayout: UICollectionViewFlowLayout!
- var comments: [String] = []
- let shortComments: [String] = [
- "First example.",
- "This is a short set... it should have a max of two lines.",
- "String with some text.",
- "This is a longer string for the two-line label.",
- "This potential solution regarding two-line-labels works better in this case.",
- "Last short string.",
- ]
- let longComments: [String] = [
- "This is a set of longer strings.",
- "Depending on the available view-width, it may not work well if the text is too long.",
- "Our final example string will be much longer than the others. This will demonstrate that, unless we also set a max-width, the calculated width will end up extending the label outside the bounds of our view (assuming we're on an iPhone in Portrait orientation).",
- "A label can contain an arbitrary amount of text, but UILabel may shrink, wrap, or truncate the text, depending on the size of the bounding rectangle and properties you set. You can control the font, text color, alignment, highlighting, and shadowing of the text in the label.",
- "You can set the title, image, and other appearance properties of a button. In addition, you can specify a different appearance for each button state.",
- "Displays a rounded rectangle that can contain editable text. When a user taps a text field, a keyboard appears; when a user taps Return in the keyboard, the keyboard disappears and the text field can handle the input in an application-specific way. UITextField supports overlay views to display additional information, such as a bookmarks icon. UITextField also provides a clear text control a user taps to erase the contents of the text field.",
- ]
- var commentToggle: Int = 0
- let titleFont: UIFont = .systemFont(ofSize: 18.0)
- let commentFont: UIFont = .systemFont(ofSize: 12.0)
- override func viewDidLoad() {
- super.viewDidLoad()
- let toggleButton = UIButton()
- toggleButton.setTitle("Toggle Data", for: [])
- toggleButton.setTitleColor(.white, for: .normal)
- toggleButton.setTitleColor(.gray, for: .highlighted)
- toggleButton.backgroundColor = .systemBlue
- toggleButton.addTarget(self, action: #selector(toggleTapped(_:)), for: .touchUpInside)
- flowLayout = UICollectionViewFlowLayout()
- flowLayout.scrollDirection = .horizontal
- collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout)
- toggleButton.translatesAutoresizingMaskIntoConstraints = false
- collectionView.translatesAutoresizingMaskIntoConstraints = false
- view.addSubview(toggleButton)
- view.addSubview(collectionView)
- let g = view.safeAreaLayoutGuide
- collectionViewHeightConstraint = collectionView.heightAnchor.constraint(equalToConstant: flowLayout.itemSize.height)
- NSLayoutConstraint.activate([
- toggleButton.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
- toggleButton.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 60.0),
- toggleButton.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -60.0),
- collectionView.topAnchor.constraint(equalTo: toggleButton.bottomAnchor, constant: 40.0),
- collectionView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
- collectionView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
- collectionViewHeightConstraint,
- ])
- collectionView.dataSource = self
- collectionView.delegate = self
- collectionView.register(CommentCell.self, forCellWithReuseIdentifier: "commentCell")
- updateViews()
- }
- func updateViews() -> Void {
- // assuming we want the cell width to be 280-pts,
- // with 8-pts "padding" on each side
- // the cell's title label and comment label Widths are: 264-pts
- let w: CGFloat = 264.0
- // Max 6 lines? Then get height of 6 lines
- let sixLines: String = "1\n2\n3\n4\n5\n6"
- let sixLineHeight: CGFloat = sixLines.height(withConstrainedWidth: w, font: commentFont)
- // start with short comments
- comments = commentToggle % 2 == 0 ? shortComments : longComments
- var maxCommentHeight: CGFloat = 0
- for i in 0..<comments.count {
- let h: CGFloat = comments[i].height(withConstrainedWidth: w, font: commentFont)
- maxCommentHeight = max(h, maxCommentHeight)
- if maxCommentHeight >= sixLineHeight {
- maxCommentHeight = sixLineHeight
- break
- }
- }
- // get height of title label
- let th: CGFloat = "A".height(withConstrainedWidth: w, font: titleFont)
- // cell height will be
- // profileImageView height (80)
- // +
- // title label height
- // +
- // maxCommentHeight
- // +
- // vertical spacing (4 spaces * 8)
- let cellHeight: CGFloat = 80.0 + th + maxCommentHeight + 32.0
- flowLayout.itemSize = CGSize(width: w + 16.0, height: cellHeight)
- collectionViewHeightConstraint.constant = flowLayout.itemSize.height
- collectionView.reloadData()
- }
- @objc func toggleTapped(_ sender: Any?) -> Void {
- commentToggle += 1
- updateViews()
- }
- }
- extension SampleViewController: UICollectionViewDataSource, UICollectionViewDelegate {
- func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
- return comments.count
- }
- func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
- let c = collectionView.dequeueReusableCell(withReuseIdentifier: "commentCell", for: indexPath) as! CommentCell
- c.titleLabel.font = titleFont
- c.commentLabel.font = commentFont
- c.commentLabel.text = comments[indexPath.item]
- return c
- }
- }
- // -------------------
- // original paste follows
- // -------------------
- // assuming comment label Width is 260-pts
- let w: CGFloat = 260.0
- // assuming font of comment label
- let font: UIFont = .systemFont(ofSize: 12.0)
- // Max 6 lines? Then get height of 6 lines
- let sixLines: String = "1\n2\n3\n4\n5\n6"
- let sixLineHeight: CGFloat = sixLines.height(withConstrainedWidth: w, font: font)
- var maxCommentHeight: CGFloat = 0
- for i in 0..<comments.count {
- let h: CGFloat = comments[i].height(withConstrainedWidth: w, font: font)
- print("h:", h)
- maxCommentHeight = max(h, maxCommentHeight)
- if maxCommentHeight > sixLineHeight {
- maxCommentHeight = sixLineHeight
- break
- }
- }
- print("Max comment height:", maxCommentHeight)
- // set itemSize of collection view flow layout to
- // CGSize(width: w, height: maxCommentHeight)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement