Skip to content

Instantly share code, notes, and snippets.

@irace
Last active June 16, 2016 16:17
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save irace/6403a45cd90195c137d64bfa76defd5a to your computer and use it in GitHub Desktop.
Save irace/6403a45cd90195c137d64bfa76defd5a to your computer and use it in GitHub Desktop.
`UITextView` should really just have this by default.
protocol TextContaining {
var isEmpty: Bool { get }
}
extension String: TextContaining {
}
extension Optional where Wrapped: TextContaining {
var isEmpty: Bool {
switch self {
case .Some(let someString):
return someString.isEmpty
default:
return true
}
}
}
final class PlaceholderTextView: UITextView {
// MARK: - Public
var placeholder: String? {
set {
placeholderLabel.text = newValue
}
get {
return placeholderLabel.text
}
}
var placeholderColor: UIColor {
set {
placeholderLabel.textColor = newValue
}
get {
return placeholderLabel.textColor
}
}
// MARK: - Private
private var labelConstraints: [NSLayoutConstraint] = []
private let placeholderLabel = UILabel().then {
$0.translatesAutoresizingMaskIntoConstraints = false
$0.lineBreakMode = .ByWordWrapping
$0.numberOfLines = 0
$0.textColor = .lightGrayColor()
}
// MARK: - UITextView
override var font: UIFont? {
didSet {
placeholderLabel.font = font
}
}
override var text: String? {
didSet {
updatePlaceholderVisibility()
}
}
// MARK: - Initialization
override init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
addSubview(placeholderLabel)
[
(UITextViewTextDidBeginEditingNotification, #selector(textFieldDidBeginEditing)),
(UITextViewTextDidEndEditingNotification, #selector(textFieldDidEndEditing))
].forEach { name, selector in
NSNotificationCenter.defaultCenter().addObserver(self, selector: selector, name: name, object: self)
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Actions
private dynamic func textFieldDidBeginEditing() {
placeholderLabel.hidden = true
}
private dynamic func textFieldDidEndEditing() {
updatePlaceholderVisibility()
}
// MARK: - UIView
override func updateConstraints() {
super.updateConstraints()
NSLayoutConstraint.deactivateConstraints(labelConstraints)
/*
These constraints are probably not totally comprehensive but should work fine in most cases (e.g. where the
text view is taller than the placeholder label).
Don’t pin to the edges because otherwise the scroll view’s content size will be impacted by the label.
*/
labelConstraints = [
placeholderLabel.centerXAnchor.constraintEqualToAnchor(centerXAnchor),
placeholderLabel.widthAnchor.constraintEqualToAnchor(widthAnchor, constant: -(textContainerInset.left + textContainerInset.right)),
placeholderLabel.topAnchor.constraintEqualToAnchor(topAnchor, constant: textContainerInset.top),
]
NSLayoutConstraint.activateConstraints(labelConstraints)
}
// MARK: - Private
private func updatePlaceholderVisibility() {
placeholderLabel.hidden = !text.isEmpty
}
}
/// https://github.com/devxoul/Then
protocol Then {
}
extension Then {
public func then(@noescape block: Self -> Void) -> Self {
block(self)
return self
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment