Created
August 17, 2022 23:37
-
-
Save christianselig/509ba9c88a6b050ab48558ea15cb0c51 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
import UIKit | |
class ViewController: UIViewController { | |
let textViewWrapper = TextViewWrapper() | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
// The problem view! I want to add this one to my set of Auto Layout constraints, | |
// even though it's not using Auto Layout internally. | |
textViewWrapper.translatesAutoresizingMaskIntoConstraints = false | |
view.addSubview(textViewWrapper) | |
// This one is well behaved. | |
let redBox = UIView() | |
redBox.backgroundColor = .systemRed | |
redBox.translatesAutoresizingMaskIntoConstraints = false | |
view.addSubview(redBox) | |
NSLayoutConstraint.activate([ | |
redBox.widthAnchor.constraint(equalToConstant: 50.0), | |
redBox.heightAnchor.constraint(equalToConstant: 50.0), | |
redBox.centerXAnchor.constraint(equalTo: view.centerXAnchor), | |
redBox.bottomAnchor.constraint(equalTo: textViewWrapper.topAnchor, constant: -50.0), | |
// Please show up 😢 | |
textViewWrapper.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), | |
textViewWrapper.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor), | |
textViewWrapper.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor) | |
]) | |
} | |
} | |
/// A simplified version of a class that holds a text view and is laid out with frames | |
/// because Auto Layout + UITextView expanding/collapsing doesn't animate well. | |
class TextViewWrapper: UIView { | |
let textView = UITextView() | |
init() { | |
super.init(frame: .zero) | |
textView.text = "Once upon a time a turtle named Lenny went to the park to meet with his friend the tiger." | |
textView.backgroundColor = .magenta.withAlphaComponent(0.05) | |
addSubview(textView) | |
} | |
@available(*, unavailable) | |
required init?(coder aDecoder: NSCoder) { fatalError("\(#file) does not implement coder.") } | |
override func layoutSubviews() { | |
super.layoutSubviews() | |
textView.frame = bounds | |
} | |
override func sizeThatFits(_ size: CGSize) -> CGSize { | |
return CGSize(width: size.width, height: textView.sizeThatFits(size).height) | |
} | |
override func systemLayoutSizeFitting(_ targetSize: CGSize) -> CGSize { | |
return CGSize(width: targetSize.width, height: textView.sizeThatFits(targetSize).height) | |
} | |
} |
This combo seems to be working for me, based on some of the suggestions in the thread:
var lastWidth = 0.0
override var intrinsicContentSize: CGSize { textView.frame.size }
override func layoutSubviews() {
super.layoutSubviews()
textView.frame = bounds
if textView.frame.width != lastWidth {
lastWidth = textView.frame.width
textView.sizeToFit()
invalidateIntrinsicContentSize()
}
}
wrote this at my coffee table w/ swift playgrounds on iPad barely working so excuse the trash quality code. It IS functional..
import UIKit
/// A simplified version of a class that holds a text view and is laid out with frames
/// because Auto Layout + UITextView expanding/collapsing doesn't animate well.
class TextViewWrapper: UIView {
lazy var textView = UITextView()
var numberOfLines: Int = 1 {
didSet {
textView.textContainer.maximumNumberOfLines = numberOfLines
setNeedsLayout()
invalidateIntrinsicContentSize()
}
}
func sharedInit() {
backgroundColor = .yellow
textView.backgroundColor = .blue
textView.isScrollEnabled = false
textView.isEditable = false
textView.textContainer.lineBreakMode = .byTruncatingTail
textView.textContainer.maximumNumberOfLines = numberOfLines
textView.translatesAutoresizingMaskIntoConstraints = false
textView.text = """
Once upon a time a turtle named Lenny went to the park to meet with his friend the tiger. He had to keep thinking of more and more text to make this text view grow. Maybe this is enough? Turns out the iPad is a beast and requires more text to wrap to a second line.
"""
addSubview(textView)
let tap = UITapGestureRecognizer(target: self, action: #selector(tapped))
addGestureRecognizer(tap)
}
override init(frame: CGRect) {
super.init(frame: frame)
sharedInit()
}
@objc func tapped() {
numberOfLines = numberOfLines == 1 ? 0 : 1
}
@available(*, unavailable)
required init?(coder aDecoder: NSCoder) { fatalError("\(#file) does not implement coder.") }
override func layoutSubviews() {
super.layoutSubviews()
textView.frame = bounds
textView.contentSize.width = frame.size.width
invalidateIntrinsicContentSize()
}
override var intrinsicContentSize: CGSize {
textView.sizeToFit()
return textView.contentSize
}
}
import UIKit
class ViewController: UIViewController {
lazy var textViewWrapper: UIView = TextViewWrapper(frame: .zero)
override func viewDidLoad() {
super.viewDidLoad()
// The problem view! I want to add this one to my set of Auto Layout constraints,
// even though it's not using Auto Layout internally.
textViewWrapper.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(textViewWrapper)
// This one is well behaved.
let redBox = UIView()
redBox.backgroundColor = .systemRed
redBox.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(redBox)
let leading = textViewWrapper.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor)
NSLayoutConstraint.activate([
redBox.widthAnchor.constraint(equalToConstant: 50.0),
redBox.heightAnchor.constraint(equalToConstant: 50.0),
redBox.centerXAnchor.constraint(equalTo: view.centerXAnchor),
redBox.bottomAnchor.constraint(equalTo: textViewWrapper.topAnchor, constant: -50.0),
textViewWrapper.leadingAnchor.constraint(greaterThanOrEqualTo: view.leadingAnchor, constant: 20),
textViewWrapper.trailingAnchor.constraint(greaterThanOrEqualTo: view.trailingAnchor, constant: 20),
textViewWrapper.centerXAnchor.constraint(equalTo: view.centerXAnchor),
textViewWrapper.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
])
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is getting closer!