123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- //
- // IQTextView.swift
- // https://github.com/hackiftekhar/IQKeyboardManager
- // Copyright (c) 2013-16 Iftekhar Qurashi.
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- import UIKit
- /** @abstract UITextView with placeholder support */
- open class IQTextView: UITextView {
- @objc required public init?(coder aDecoder: NSCoder) {
- super.init(coder: aDecoder)
- #if swift(>=4.2)
- let UITextViewTextDidChange = UITextView.textDidChangeNotification
- #else
- let UITextViewTextDidChange = Notification.Name.UITextViewTextDidChange
- #endif
- NotificationCenter.default.addObserver(self, selector: #selector(self.refreshPlaceholder), name: UITextViewTextDidChange, object: self)
- }
- @objc override public init(frame: CGRect, textContainer: NSTextContainer?) {
- super.init(frame: frame, textContainer: textContainer)
- #if swift(>=4.2)
- let notificationName = UITextView.textDidChangeNotification
- #else
- let notificationName = Notification.Name.UITextViewTextDidChange
- #endif
- NotificationCenter.default.addObserver(self, selector: #selector(self.refreshPlaceholder), name: notificationName, object: self)
- }
- @objc override open func awakeFromNib() {
- super.awakeFromNib()
- #if swift(>=4.2)
- let UITextViewTextDidChange = UITextView.textDidChangeNotification
- #else
- let UITextViewTextDidChange = Notification.Name.UITextViewTextDidChange
- #endif
- NotificationCenter.default.addObserver(self, selector: #selector(self.refreshPlaceholder), name: UITextViewTextDidChange, object: self)
- }
- deinit {
- placeholderLabel.removeFromSuperview()
- NotificationCenter.default.removeObserver(self)
- }
- private var placeholderInsets: UIEdgeInsets {
- return UIEdgeInsets(top: self.textContainerInset.top, left: self.textContainerInset.left + self.textContainer.lineFragmentPadding, bottom: self.textContainerInset.bottom, right: self.textContainerInset.right + self.textContainer.lineFragmentPadding)
- }
- private var placeholderExpectedFrame: CGRect {
- let placeholderInsets = self.placeholderInsets
- let maxWidth = self.frame.width-placeholderInsets.left-placeholderInsets.right
- let expectedSize = placeholderLabel.sizeThatFits(CGSize(width: maxWidth, height: self.frame.height-placeholderInsets.top-placeholderInsets.bottom))
- return CGRect(x: placeholderInsets.left, y: placeholderInsets.top, width: maxWidth, height: expectedSize.height)
- }
- lazy var placeholderLabel: UILabel = {
- let label = UILabel()
- label.autoresizingMask = [.flexibleWidth, .flexibleHeight]
- label.lineBreakMode = .byWordWrapping
- label.numberOfLines = 0
- label.font = self.font
- label.textAlignment = self.textAlignment
- label.backgroundColor = UIColor.clear
- label.textColor = UIColor(white: 0.7, alpha: 1.0)
- label.alpha = 0
- self.addSubview(label)
- return label
- }()
- /** @abstract To set textView's placeholder text color. */
- @IBInspectable open var placeholderTextColor: UIColor? {
- get {
- return placeholderLabel.textColor
- }
- set {
- placeholderLabel.textColor = newValue
- }
- }
- /** @abstract To set textView's placeholder text. Default is nil. */
- @IBInspectable open var placeholder: String? {
- get {
- return placeholderLabel.text
- }
- set {
- placeholderLabel.text = newValue
- refreshPlaceholder()
- }
- }
- /** @abstract To set textView's placeholder attributed text. Default is nil. */
- open var attributedPlaceholder: NSAttributedString? {
- get {
- return placeholderLabel.attributedText
- }
- set {
- placeholderLabel.attributedText = newValue
- refreshPlaceholder()
- }
- }
- @objc override open func layoutSubviews() {
- super.layoutSubviews()
- placeholderLabel.frame = placeholderExpectedFrame
- }
- @objc internal func refreshPlaceholder() {
- if !text.isEmpty || !attributedText.string.isEmpty {
- placeholderLabel.alpha = 0
- } else {
- placeholderLabel.alpha = 1
- }
- }
- @objc override open var text: String! {
- didSet {
- refreshPlaceholder()
- }
- }
- open override var attributedText: NSAttributedString! {
- didSet {
- refreshPlaceholder()
- }
- }
- @objc override open var font: UIFont? {
- didSet {
- if let unwrappedFont = font {
- placeholderLabel.font = unwrappedFont
- } else {
- placeholderLabel.font = UIFont.systemFont(ofSize: 12)
- }
- }
- }
- @objc override open var textAlignment: NSTextAlignment {
- didSet {
- placeholderLabel.textAlignment = textAlignment
- }
- }
- @objc override open var delegate: UITextViewDelegate? {
- get {
- refreshPlaceholder()
- return super.delegate
- }
- set {
- super.delegate = newValue
- }
- }
- @objc override open var intrinsicContentSize: CGSize {
- guard !hasText else {
- return super.intrinsicContentSize
- }
- var newSize = super.intrinsicContentSize
- let placeholderInsets = self.placeholderInsets
- newSize.height = placeholderExpectedFrame.height + placeholderInsets.top + placeholderInsets.bottom
- return newSize
- }
- }
|