如何在UITextView中添加占位符,类似于你可以为UITextField设置的占位符,在Swift中?


当前回答

斯威夫特3.1

这个扩展为我工作得很好:https://github.com/devxoul/UITextView-Placeholder

下面是一个代码片段:

通过pod安装:

pod 'UITextView+Placeholder', '~> 1.2'

将它导入到类中

import UITextView_Placeholder

并添加占位符属性到您已经创建的UITextView

textView.placeholder = "Put some detail"

这是…… 这里是它的外观(第三个框是一个UITextView)

其他回答

这里有一些东西可以被放到UIStackView中,它会使用内部高度约束来调整自己的大小。可能需要调整以适应特定的需求。

import UIKit

public protocol PlaceholderTextViewDelegate: class {
  func placeholderTextViewTextChanged(_ textView: PlaceholderTextView, text: String)
}

public class PlaceholderTextView: UIView {

  public weak var delegate: PlaceholderTextViewDelegate?
  private var heightConstraint: NSLayoutConstraint?

  public override init(frame: CGRect) {
    self.allowsNewLines = true

    super.init(frame: frame)

    self.heightConstraint = self.heightAnchor.constraint(equalToConstant: 0)
    self.heightConstraint?.isActive = true

    self.addSubview(self.placeholderTextView)
    self.addSubview(self.textView)

    self.pinToCorners(self.placeholderTextView)
    self.pinToCorners(self.textView)

    self.updateHeight()
  }

  public override func didMoveToSuperview() {
    super.didMoveToSuperview()

    self.updateHeight()
  }

  private func pinToCorners(_ view: UIView) {
    NSLayoutConstraint.activate([
      view.leadingAnchor.constraint(equalTo: self.leadingAnchor),
      view.trailingAnchor.constraint(equalTo: self.trailingAnchor),
      view.topAnchor.constraint(equalTo: self.topAnchor),
      view.bottomAnchor.constraint(equalTo: self.bottomAnchor)
    ])
  }

  // Accessors
  public var text: String? {
    didSet {
      self.textView.text = text
      self.textViewDidChange(self.textView)
      self.updateHeight()
    }
  }

  public var textColor: UIColor? {
    didSet {
      self.textView.textColor = textColor
      self.updateHeight()
    }
  }

  public var font: UIFont? {
    didSet {
      self.textView.font = font
      self.placeholderTextView.font = font
      self.updateHeight()
    }
  }

  public override var tintColor: UIColor? {
    didSet {
      self.textView.tintColor = tintColor
      self.placeholderTextView.tintColor = tintColor
    }
  }

  public var placeholderText: String? {
    didSet {
      self.placeholderTextView.text = placeholderText
      self.updateHeight()
    }
  }

  public var placeholderTextColor: UIColor? {
    didSet {
      self.placeholderTextView.textColor = placeholderTextColor
      self.updateHeight()
    }
  }

  public var allowsNewLines: Bool

  public required init?(coder _: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  private lazy var textView: UITextView = self.newTextView()
  private lazy var placeholderTextView: UITextView = self.newTextView()

  private func newTextView() -> UITextView {
    let textView = UITextView()
    textView.translatesAutoresizingMaskIntoConstraints = false
    textView.isScrollEnabled = false
    textView.delegate = self
    textView.backgroundColor = .clear
    return textView
  }

  private func updateHeight() {
    let maxSize = CGSize(width: self.frame.size.width, height: .greatestFiniteMagnitude)

    let textViewSize = self.textView.sizeThatFits(maxSize)
    let placeholderSize = self.placeholderTextView.sizeThatFits(maxSize)

    let maxHeight = ceil(CGFloat.maximum(textViewSize.height, placeholderSize.height))

    self.heightConstraint?.constant = maxHeight
  }
}

extension PlaceholderTextView: UITextViewDelegate {
  public func textViewDidChangeSelection(_: UITextView) {
    self.placeholderTextView.alpha = self.textView.text.isEmpty ? 1 : 0
    self.updateHeight()
  }

  public func textViewDidChange(_: UITextView) {
    self.delegate?.placeholderTextViewTextChanged(self, text: self.textView.text)
  }

  public func textView(_: UITextView, shouldChangeTextIn _: NSRange,
                       replacementText text: String) -> Bool {
    let containsNewLines = text.rangeOfCharacter(from: .newlines)?.isEmpty == .some(false)
    guard !containsNewLines || self.allowsNewLines else { return false }

    return true
  }
}

协议版本的clearlight的答案上面,因为协议是伟大的。随便放哪都行。扣篮!

extension UITextViewPlaceholder where Self: UIViewController {

    // Use this in ViewController's ViewDidLoad method.
    func addPlaceholder(text: String, toTextView: UITextView, font: UIFont? = nil) {
        placeholderLabel = UILabel()
        placeholderLabel.text = text
        placeholderLabel.font = font ?? UIFont.italicSystemFont(ofSize: (toTextView.font?.pointSize)!)
        placeholderLabel.sizeToFit()
        toTextView.addSubview(placeholderLabel)
        placeholderLabel.frame.origin = CGPoint(x: 5, y: (toTextView.font?.pointSize)! / 2)
        placeholderLabel.textColor = UIColor.lightGray
        placeholderLabel.isHidden = !toTextView.text.isEmpty
    }

    // Use this function in the ViewController's textViewDidChange delegate method.
    func textViewWithPlaceholderDidChange(_ textView: UITextView) {
        placeholderLabel.isHidden = !textView.text.isEmpty
    }
}
import UIKit
import RxSwift

@IBDesignable class TextViewWithPlaceholder: UITextView {
    
    //MARK: - Propertise
    @IBInspectable var placeholderText: String = ""
    
    let placeholderLabel = LocalizedUILabel()
    private let hidePlaceholderObserver = PublishSubject<Bool>()
    let disposeBag = DisposeBag()
    
    
    //MARK: - Did Move To Window
    override func didMoveToWindow() {
        super.didMoveToWindow()
        observeOnTextViewEditing()
        configurePlaceholder()
    }
    
    
    //MARK: - Observe On Text View Editing
    private func observeOnTextViewEditing() {
        rx.text.subscribe(onNext: { [weak self] selectedText in
            guard let self = self else { return }
            self.hidePlaceholderObserver.onNext((selectedText?.isEmpty ?? true) ? false : true)
            
        }).disposed(by: disposeBag)
    }
    
    
    //MARK: - Observe On Show Hide Placeholder
    private func configurePlaceholder() {
        hidePlaceholderObserver
            .bind(to: placeholderLabel.rx.isHidden)
            .disposed(by: disposeBag)
        
        placeholderLabel.text = placeholderText
        placeholderLabel.font = UIFont(name: "Poppins-Semibold", size: 16) ?? UIFont()
        placeholderLabel.textColor = .lightGray
        
        placeholderLabel.sizeToFit()
        placeholderLabel.frame.origin = CGPoint(x: 8, y: 8)
        addSubview(placeholderLabel)
    }
    
}

有我的简单版本的UITextView与占位符。主要思想是:

隐藏占位符,如果用户开始编辑和占位符是可见的 如果用户结束编辑并且文本视图的文本为空,则显示占位符。

class PlaceholderTextView: UITextView {

    var placeholder = "" {
        didSet {
            if isPlaceholderVisible {
                showPlaceholder()
            }
        }
    }

    var isPlaceholderVisible = true {
        didSet {
            isPlaceholderVisible ? showPlaceholder() : hidePlaceholder()
        }
    }

    init() {
        super.init(frame: .zero, textContainer: nil)
        delegate = self
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    private func showPlaceholder() {
        text = placeholder
        // Set other things like color of text for placeholder, ...
    }

    private func hidePlaceholder() {
        text = ""
        // Set other things like color of text for normal input, ...
    }

}

extension PlaceholderTextView: UITextViewDelegate {
    func textViewDidBeginEditing(_ textView: UITextView) {
        if isPlaceholderVisible {
            isPlaceholderVisible = false
        }
    }

    func textViewDidEndEditing(_ textView: UITextView) {
        if text.isEmpty {
            isPlaceholderVisible = true
        }
    }
}

我试着用clearlight的答案来简化代码。

extension UITextView{

    func setPlaceholder() {

        let placeholderLabel = UILabel()
        placeholderLabel.text = "Enter some text..."
        placeholderLabel.font = UIFont.italicSystemFont(ofSize: (self.font?.pointSize)!)
        placeholderLabel.sizeToFit()
        placeholderLabel.tag = 222
        placeholderLabel.frame.origin = CGPoint(x: 5, y: (self.font?.pointSize)! / 2)
        placeholderLabel.textColor = UIColor.lightGray
        placeholderLabel.isHidden = !self.text.isEmpty

        self.addSubview(placeholderLabel)
    }

    func checkPlaceholder() {
        let placeholderLabel = self.viewWithTag(222) as! UILabel
        placeholderLabel.isHidden = !self.text.isEmpty
    }

}

使用

override func viewDidLoad() {
    textView.delegate = self
    textView.setPlaceholder()
}

func textViewDidChange(_ textView: UITextView) {
    textView.checkPlaceholder()
}