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


当前回答

Swift 4、4.2和5

[![@IBOutlet var detailTextView: UITextView!

override func viewDidLoad() {
        super.viewDidLoad()
        detailTextView.delegate = self
}

extension ContactUsViewController : UITextViewDelegate {

    public func textViewDidBeginEditing(_ textView: UITextView) {
        if textView.text == "Write your message here..." {
            detailTextView.text = ""
            detailTextView.textColor = UIColor.init(red: 0/255, green: 0/255, blue: 0/255, alpha: 0.86)

        }
        textView.becomeFirstResponder()
    }

    public func textViewDidEndEditing(_ textView: UITextView) {

        if textView.text == "" {
            detailTextView.text = "Write your message here..."
            detailTextView.textColor = UIColor.init(red: 0/255, green: 0/255, blue: 0/255, alpha: 0.30)
        }
        textView.resignFirstResponder()
    }
[![}][1]][1]

其他回答

我不知道为什么人们会把这个问题复杂化....这是相当直接和简单的。下面是UITextView的一个子类,它提供了所请求的功能。

- (void)customInit
{
    self.contentMode = UIViewContentModeRedraw;
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChanged:) name:UITextViewTextDidChangeNotification object:nil];
}

    - (void)textChanged:(NSNotification *)notification
    {
        if (notification.object == self) {
            if(self.textStorage.length != 0 || !self.textStorage.length) {
                [self setNeedsDisplay];
            }
        }
    }


    #pragma mark - Setters

    - (void)setPlaceholderText:(NSString *)placeholderText withFont:(UIFont *)font
    {
        self.placeholderText = placeholderText;
        self.placeholderTextFont = font;

    }



    - (void)drawRect:(CGRect)rect
    {
        [super drawRect:rect];
        [[UIColor lightGrayColor] setFill];

        if (self.textStorage.length != 0) {
            return;
        }

        CGRect inset = CGRectInset(rect, 8, 8);//Default rect insets for textView
        NSDictionary *attributes =  @{NSFontAttributeName: self.placeholderTextFont, NSForegroundColorAttributeName: [UIColor grayColor]};
        [self.placeholderText drawInRect:inset withAttributes:attributes];
    }`

我们的解决方案避免了与UITextView文本和textColor属性的混淆,如果您要维护字符计数器,这是非常方便的。

很简单:

1)在Storyboard中创建一个与主UITextView属性相同的虚拟UITextView。将占位符文本分配给虚拟文本。

2)对齐两个uitextview的上、左、右边缘。

3)把假人放在主人的后面。

4)重写master的textViewDidChange(textView:)委托函数,如果master有0个字符,则显示dummy。否则,显示master。

这假设两个uitextview的背景都是透明的。如果没有,当有0个字符时,将假人放在上面,当有>个0个字符时,将它推到下面。您还必须交换响应器,以确保光标跟随正确的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
  }
}
var placeholderLabel : UILabel!
  textviewDescription.delegate = self
    placeholderLabel = UILabel()
    placeholderLabel.text = "Add a description"

   func textViewDidChange(_ textView: UITextView) {
             placeholderLabel.isHidden = !textviewDescription.text.isEmpty
    }

我不得不调度队列,让我的占位符文本重新出现,一旦编辑完成。

func textViewDidBeginEditing(_ textView: UITextView) {

    if textView.text == "Description" {
        textView.text = nil
    }
}

func textViewDidEndEditing(_ textView: UITextView) {

    if textView.text.isEmpty {
        DispatchQueue.main.async {
            textView.text = "Description"
        }
    }
}