| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 |
- //
- // IBTextView.swift
- // MTP2_iOS
- //
- // Created by Handy_Cao on 2018/8/9.
- // Copyright © 2018年 Muchinfo. All rights reserved.
- //
- import UIKit
- @IBDesignable
- class IBTextView: UITextView, UITextViewDelegate {
-
- /// 默认最大行高
- var maxRowHeight:CGFloat = 100
- /// 默认样式
- var borderStyle: IBTextViewStyle = .default {
- didSet {
- switch borderStyle {
- case .default:
- defaultSetting()
- case .NoneBorder:
- noneBorderSetting()
- case .custom:
- customBorderSetting()
- }
- }
- }
- /// IBTextView高度变化通知
- static let RowChangeNotification = NSNotification.Name.init("IBTextViewRowChange")
- /// delegate
- weak var IBTextViewDelegate: UITextViewDelegate?
-
- /// 样式
- ///
- /// - `default`: 默认样式
- /// - NoneBorder: 无边框样式
- /// - custom: 自定义样式,由IB决定
- enum IBTextViewStyle {
- case `default`
- case NoneBorder
- case custom
- }
-
- @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)
- delegate = 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)
- delegate = 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)
- delegate = self
- }
-
- private func defaultSetting() {
- layer.borderColor = UIColor(red: 215.0 / 255.0, green: 215.0 / 255.0, blue: 215.0 / 255.0, alpha: 1).cgColor
- layer.borderWidth = 0.6
- layer.cornerRadius = 6.0
- }
-
- private func noneBorderSetting() {
- layer.borderColor = nil
- layer.borderWidth = 0
- layer.cornerRadius = 0
- }
-
- private func customBorderSetting() {
- // 由IB决定
- }
-
- 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 borderColor. Default is nil. */
- @IBInspectable open var borderColor : UIColor? {
-
- get {
- if let borderColor = layer.borderColor {
- return UIColor(cgColor: borderColor)
- } else {
- return nil
- }
- }
-
- set {
- if let newValue = newValue {
- layer.borderColor = newValue.cgColor
- } else {
- layer.borderColor = UIColor(red: 215.0 / 255.0, green: 215.0 / 255.0, blue: 215.0 / 255.0, alpha: 1).cgColor
- }
- }
- }
-
- /** @abstract To set textView's borderWidth. Default is 0. */
- @IBInspectable open var borderWidth : CGFloat {
-
- get {
- return layer.borderWidth
- }
-
- set {
- layer.borderWidth = newValue
- }
- }
-
- /** @abstract To set textView's cornerRadius. Default is 0. */
- @IBInspectable open var cornerRadius : CGFloat {
-
- get {
- return layer.cornerRadius
- }
-
- set {
- layer.cornerRadius = newValue
- }
- }
-
-
-
- /** @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 internal var delegate : UITextViewDelegate? {
-
- get {
- refreshPlaceholder()
- return super.delegate
- }
-
- set {
- super.delegate = newValue
- }
- }
-
- @objc override open var intrinsicContentSize: CGSize {
- guard !hasText else {
- var newSize = super.intrinsicContentSize
- newSize.height = 30
- return newSize
- }
-
- var newSize = super.intrinsicContentSize
- let placeholderInsets = self.placeholderInsets
- newSize.height = placeholderExpectedFrame.height + placeholderInsets.top + placeholderInsets.bottom
-
- return newSize
- }
-
- //MARK: - UITextViewDelegate
- func textViewDidChange(_ textView: UITextView) {
- let frame = textView.frame
- let constraintSize = CGSize(width: frame.width, height: CGFloat(MAXFLOAT))
- let size = textView.sizeThatFits(constraintSize)
- if size.height <= maxRowHeight {
- let constraints = textView.constraints.filter({ $0.firstAttribute == NSLayoutConstraint.Attribute.height })
- if constraints.count > 0 {
- textView.removeConstraints(constraints)
- }
- let newConstraints = NSLayoutConstraint(item: textView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: size.height)
- newConstraints.priority = UILayoutPriority(rawValue: 999)
- textView.addConstraint(newConstraints)
-
- NotificationCenter.default.post(name: IBTextView.RowChangeNotification, object: nil)
- } else {
- let constraints = textView.constraints.filter({ $0.firstAttribute == NSLayoutConstraint.Attribute.height })
- if constraints.count > 0 {
- textView.removeConstraints(constraints)
- }
- let newConstraints = NSLayoutConstraint(item: textView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: maxRowHeight)
- newConstraints.priority = UILayoutPriority(rawValue: 999)
- textView.addConstraint(newConstraints)
-
- NotificationCenter.default.post(name: IBTextView.RowChangeNotification, object: nil)
- }
- }
-
- func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
- return IBTextViewDelegate?.textViewShouldEndEditing?(textView) ?? true
- }
-
- func textViewShouldEndEditing(_ textView: UITextView) -> Bool {
- return IBTextViewDelegate?.textViewShouldEndEditing?(textView) ?? true
- }
-
- func textViewDidBeginEditing(_ textView: UITextView) {
- IBTextViewDelegate?.textViewDidBeginEditing?(textView)
- }
-
- func textViewDidEndEditing(_ textView: UITextView) {
- IBTextViewDelegate?.textViewDidEndEditing?(textView)
- }
-
- func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
- return IBTextViewDelegate?.textView?(textView, shouldChangeTextIn: range, replacementText: text) ?? true
- }
- }
|