Skip to content

Instantly share code, notes, and snippets.

@IanKeen
Created June 5, 2019 15:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save IanKeen/2e8a5d8644bfc414c6ce51c79de66509 to your computer and use it in GitHub Desktop.
Save IanKeen/2e8a5d8644bfc414c6ce51c79de66509 to your computer and use it in GitHub Desktop.
UITextView with some commonly needed additions
import UIKit
open class TextView: UITextView {
// MARK: - Public Properties
public var autoSizing: Bool = false {
didSet { redraw() }
}
public var minimumLines: Int = 1 {
didSet { redraw() }
}
public var maximumLines: Int = 10 {
didSet { redraw() }
}
public var placeholderText: String? = "" {
didSet { redraw() }
}
public var placeholderTextFont: UIFont? {
didSet { redraw() }
}
public var placeholderTextColor: UIColor = .lightGray {
didSet { redraw() }
}
// MARK: - Private Properties
private lazy var placeholderLabel: UILabel = {
let label = UILabel()
label.backgroundColor = .clear
insertSubview(label, at: 0)
return label
}()
public override init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
configure()
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
configure()
}
private func configure() {
NotificationCenter.default.addObserver(self, selector: #selector(redraw), name: UITextView.textDidChangeNotification, object: self)
redraw()
}
open override func layoutSubviews() {
super.layoutSubviews()
let x = textContainer.lineFragmentPadding
let y = textContainerInset.top
let width = bounds.width - (x * 2)
let height = placeholderLabel.font!.lineHeight
placeholderLabel.frame = CGRect(
x: x, y: y,
width: width, height: height
)
}
// MARK: - Private Functions
@objc private func redraw() {
invalidateIntrinsicContentSize()
placeholderLabel.text = placeholderText
placeholderLabel.font = placeholderTextFont ?? font
placeholderLabel.textColor = placeholderTextColor
placeholderLabel.isHidden = placeholderText == nil || !text.isEmpty
}
// MARK: - Overrides
open override var intrinsicContentSize: CGSize {
guard autoSizing, let font = font else { return super.intrinsicContentSize }
let insets = textContainerInset.top + textContainerInset.bottom
let numberOfLines = (contentSize.height - insets) / font.lineHeight
let height = (numberOfLines.rounded(.up) * font.lineHeight) + insets
return CGSize(width: UIView.noIntrinsicMetric, height: height)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment