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


当前回答

不,没有任何占位符可用的textview。你必须把标签上面,当用户进入textview,然后隐藏它或设置默认值时,用户输入删除所有值。

其他回答

这是我准备使用的解决方案,如果您正在处理多个文本视图

func textViewShouldBeginEditing(textView: UITextView) -> Bool {        
    // Set cursor to the beginning if placeholder is set
    if textView.textColor == UIColor.lightGrayColor() {
        textView.selectedTextRange = textView.textRangeFromPosition(textView.beginningOfDocument, toPosition: textView.beginningOfDocument)
    }

    return true
}

func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
    // Remove placeholder
    if textView.textColor == UIColor.lightGrayColor() && text.characters.count > 0 {
        textView.text = ""
        textView.textColor = UIColor.blackColor()
    }

    if text == "\n" {
        textView.resignFirstResponder()
        return false
    }

    return true
}

func textViewDidChange(textView: UITextView) {
    // Set placeholder if text is empty
    if textView.text.isEmpty {
        textView.text = NSLocalizedString("Hint", comment: "hint")
        textView.textColor = UIColor.lightGrayColor()
        textView.selectedTextRange = textView.textRangeFromPosition(textView.beginningOfDocument, toPosition: textView.beginningOfDocument)
    }
}

func textViewDidChangeSelection(textView: UITextView) {
    // Set cursor to the beginning if placeholder is set
    let firstPosition = textView.textRangeFromPosition(textView.beginningOfDocument, toPosition: textView.beginningOfDocument)

    // Do not change position recursively
    if textView.textColor == UIColor.lightGrayColor() && textView.selectedTextRange != firstPosition {
        textView.selectedTextRange = firstPosition
    }
}

协议版本的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子类组合在一起,它是:

包括可配置的占位符文本,样式就像UITextField一样。 不需要任何额外的子视图或约束。 不需要来自ViewController的任何委托或其他行为。 不需要任何通知。 保持占位符文本与查看字段文本属性的任何外部类完全分离。

任何改进建议都是受欢迎的,特别是如果有任何方法通过编程来获取iOS的占位符颜色,而不是硬编码它。

斯威夫特v5:

import UIKit
@IBDesignable class TextViewWithPlaceholder: UITextView {
    
    override var text: String! { // Ensures that the placeholder text is never returned as the field's text
        get {
            if showingPlaceholder {
                return "" // When showing the placeholder, there's no real text to return
            } else { return super.text }
        }
        set { super.text = newValue }
    }
    @IBInspectable var placeholderText: String = ""
    @IBInspectable var placeholderTextColor: UIColor = UIColor(red: 0.78, green: 0.78, blue: 0.80, alpha: 1.0) // Standard iOS placeholder color (#C7C7CD). See https://stackoverflow.com/questions/31057746/whats-the-default-color-for-placeholder-text-in-uitextfield
    private var showingPlaceholder: Bool = true // Keeps track of whether the field is currently showing a placeholder
    
    override func didMoveToWindow() {
        super.didMoveToWindow()
        if text.isEmpty {
            showPlaceholderText() // Load up the placeholder text when first appearing, but not if coming back to a view where text was already entered
        }
    }
    
    override func becomeFirstResponder() -> Bool {
        // If the current text is the placeholder, remove it
        if showingPlaceholder {
            text = nil
            textColor = nil // Put the text back to the default, unmodified color
            showingPlaceholder = false
        }
        return super.becomeFirstResponder()
    }
    
    override func resignFirstResponder() -> Bool {
        // If there's no text, put the placeholder back
        if text.isEmpty {
            showPlaceholderText()
        }
        return super.resignFirstResponder()
    }
    
    private func showPlaceholderText() {
        showingPlaceholder = true
        textColor = placeholderTextColor
        text = placeholderText
    }
}

我相信这是一个非常干净的解决方案。它在实际文本视图下面添加了一个虚拟文本视图,并根据实际文本视图中的文本显示或隐藏它:

import Foundation
import UIKit

class TextViewWithPlaceholder: UITextView {

    private var placeholderTextView: UITextView = UITextView()

    var placeholder: String? {
        didSet {
            placeholderTextView.text = placeholder
        }
    }

    override var text: String! {
        didSet {
            placeholderTextView.isHidden = text.isEmpty == false
        }
    }

    override init(frame: CGRect, textContainer: NSTextContainer?) {
        super.init(frame: frame, textContainer: textContainer)
        commonInit()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }

    private func commonInit() {
        applyCommonTextViewAttributes(to: self)
        configureMainTextView()
        addPlaceholderTextView()
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(textDidChange),
                                               name: UITextView.textDidChangeNotification,
                                               object: nil)
    }

    func addPlaceholderTextView() {
        applyCommonTextViewAttributes(to: placeholderTextView)
        configurePlaceholderTextView()
        insertSubview(placeholderTextView, at: 0)
    }

    private func applyCommonTextViewAttributes(to textView: UITextView) {
        textView.translatesAutoresizingMaskIntoConstraints = false
        textView.textContainer.lineFragmentPadding = 0
        textView.textContainerInset = UIEdgeInsets(top: 10,
                                                   left: 10,
                                                   bottom: 10,
                                                   right: 10)
    }

    private func configureMainTextView() {
        // Do any configuration of the actual text view here
    }

    private func configurePlaceholderTextView() {
        placeholderTextView.text = placeholder
        placeholderTextView.font = font
        placeholderTextView.textColor = UIColor.lightGray
        placeholderTextView.frame = bounds
        placeholderTextView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        placeholderTextView.frame = bounds
    }

    @objc func textDidChange() {
        placeholderTextView.isHidden = !text.isEmpty
    }

}