(Swift) 自定义UITextView

自定义UITextView,支持placeholder、placeholderFont、placeholderColor

  • 使用方法
//lazy var textView = TextView()
//view.addSubview(textView)
//textView.frame = CGRect(x: 0, y: 0, width: 400, height: 400)
//textView.center = view.center
//textView.placeholder = "请输入内容..."
//textView.placeholderFont = .systemFont(ofSize: 20.0)
//textView.placeholderColor = .orange
//textView.backgroundColor = .lightGray
//textView.font = .systemFont(ofSize: 30.0)
//textView.textContainerInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
  • 源码分享
class TextView: UITextView {
    
    /// 占位符
    var placeholder: String? {
        willSet {
            placeholderLabel.text = newValue
            updatePlaceholderVisibility()
        }
    }
    
    /// 占位字体
    var placeholderFont: UIFont? {
        willSet {
            placeholderLabel.font = newValue
            layoutPlaceholderLabel()
        }
    }
    
    /// 占位颜色
    var placeholderColor: UIColor? {
        willSet {
            placeholderLabel.textColor = newValue
        }
    }
        
    /// override text
    override var text: String! {
        didSet {
            updatePlaceholderVisibility()
        }
    }
    
    /// override textContainerInset
    override var textContainerInset: UIEdgeInsets {
        didSet {
            layoutPlaceholderLabel()
        }
    }
    
    /// 占位UILabel
    private lazy var placeholderLabel: UILabel = {
        let label = UILabel()
        label.numberOfLines = 0
        label.text = placeholder
        label.textColor = textColor
        label.font = .systemFont(ofSize: 17.0)
        label.lineBreakMode = .byWordWrapping
        return label
    }()
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override init(frame: CGRect, textContainer: NSTextContainer?) {
        super.init(frame: frame, textContainer: textContainer)
        defaultConfig()
        setupPlaceholderLabel()
        addKeyboardNotifications()
        addObserverForTextChange()
        updatePlaceholderVisibility()
    }
    
    deinit {
        removeKeyboardNotifications()
        removeObserverForTextChange()
    }
    
    private func defaultConfig() {
        textContainerInset = .zero
        font = .systemFont(ofSize: 17.0)
        textContainer.lineFragmentPadding = 0
    }
            
    private func setupPlaceholderLabel() {
        if placeholderLabel.superview == nil {
            addSubview(placeholderLabel)
            layoutPlaceholderLabel()
        }
    }
    
    private func updatePlaceholderVisibility() {
        placeholderLabel.isHidden = !text.isEmpty
    }
    
    private func layoutPlaceholderLabel() {
        if textContainerInset == UIEdgeInsets.zero {
            if let containerView = value(forKey: "containerView") as? UIView {
                placeholderLabel.frame = containerView.frame
            }
        } else {
            let insets = textContainerInset
            let size = placeholderLabel.sizeThatFits(bounds.inset(by: insets).size)
            let origin = CGPoint(x: insets.left, y: insets.top)
            placeholderLabel.frame = CGRect(origin: origin, size: size)
        }
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        layoutIfNeeded()
        layoutPlaceholderLabel()
    }
}

extension TextView {
    private func addKeyboardNotifications() {
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
    }
    
    private func removeKeyboardNotifications() {
        NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
    }
    
    /// 监听键盘弹起
    @objc private func keyboardWillShow(notification: Notification) {
        placeholderLabel.isHidden = true
    }
    
    /// 监听键盘隐藏
    @objc private func keyboardWillHide(notification: Notification) {
        updatePlaceholderVisibility()
    }
}

extension TextView {
    private func addObserverForTextChange() {
        NotificationCenter.default.addObserver(self, selector: #selector(textDidChange), name: UITextView.textDidChangeNotification, object: self)
    }
    
    private func removeObserverForTextChange() {
        NotificationCenter.default.removeObserver(self, name: UITextView.textDidChangeNotification, object: self)
    }
    
    /// 监听文本内容更改
    @objc private func textDidChange(notification: Notification) {
        updatePlaceholderVisibility()
    }
}

更多组件 GitHub

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容