Created
April 11, 2016 23:16
-
-
Save BobDickinson/65095be27baa53820e45fc8484df6737 to your computer and use it in GitHub Desktop.
Multi-line UITextView with background and placeholder functionality of UITextField
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
// This class is necessary to support "inset" (required to position placeholder appropriately | |
// in TextView) | |
// | |
class TextField: UITextField | |
{ | |
var inset: UIEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0); | |
override func textRectForBounds(bounds: CGRect) -> CGRect | |
{ | |
return UIEdgeInsetsInsetRect(bounds, inset); | |
} | |
override func placeholderRectForBounds(bounds: CGRect) -> CGRect | |
{ | |
return UIEdgeInsetsInsetRect(bounds, inset); | |
} | |
} | |
// This class implements a UITextView that has a UITextField behind it, where the UITextField | |
// provides the border and the placeholder text functionality (so that the TextView looks and | |
// works like a UITextField in those respects). | |
// | |
class TextView : UITextView, UITextViewDelegate | |
{ | |
var textField = TextField(); | |
required init?(coder: NSCoder) | |
{ | |
fatalError("This class doesn't support NSCoding.") | |
} | |
override init(frame: CGRect, textContainer: NSTextContainer?) | |
{ | |
super.init(frame: frame, textContainer: textContainer); | |
self.delegate = self; | |
// Create a background TextField with clear (invisible) text and disabled | |
self.textField.borderStyle = UITextBorderStyle.RoundedRect; | |
self.textField.textColor = UIColor.clearColor(); | |
self.textField.userInteractionEnabled = false; | |
// Align the background TextView to where text appears in the TextField, so that any | |
// placeholder will be in the correct position. | |
self.textField.contentVerticalAlignment = UIControlContentVerticalAlignment.Top; | |
self.textField.inset = UIEdgeInsets( | |
top: self.textContainerInset.top, | |
left: self.textContainerInset.left + self.textContainer.lineFragmentPadding, | |
bottom: self.textContainerInset.bottom, | |
right: self.textContainerInset.right | |
); | |
// The background TextField should use the same font (for the placeholder) | |
self.textField.font = self.font; | |
self.addSubview(textField); | |
self.sendSubviewToBack(textField); | |
} | |
convenience init() | |
{ | |
self.init(frame: CGRectZero, textContainer: nil) | |
} | |
override var font: UIFont? | |
{ | |
didSet | |
{ | |
// Keep the font of the TextView and background textField in sync | |
self.textField.font = self.font; | |
} | |
} | |
var placeholder: String? = nil | |
{ | |
didSet | |
{ | |
self.textField.placeholder = self.placeholder; | |
} | |
} | |
override func layoutSubviews() | |
{ | |
super.layoutSubviews() | |
// Do not scroll the background textView | |
self.textField.frame = CGRectMake(0, self.contentOffset.y, self.frame.width, self.frame.height); | |
} | |
// UITextViewDelegate - Note: If you replace delegate, your delegate must call this | |
func scrollViewDidScroll(scrollView: UIScrollView) | |
{ | |
// Do not scroll the background textView | |
self.textField.frame = CGRectMake(0, self.contentOffset.y, self.frame.width, self.frame.height); | |
} | |
// UITextViewDelegate - Note: If you replace delegate, your delegate must call this | |
func textViewDidChange(textView: UITextView) | |
{ | |
// Updating the text in the background textView will cause the placeholder to appear/disappear | |
// (including any animations of that behavior - since the textView is doing this itself). | |
self.textField.text = self.text; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment