我的应用程序使用UITextView。现在我想让UITextView有一个占位符,类似于你可以为UITextField设置的占位符。

如何做到这一点?


当前回答

这是我的版本的UITextView与占位符支持。斯威夫特4.2 https://gist.github.com/hlung/c5dda3a0c2087e5ae6c1fce8822c4713

一个支持占位符文本的UITextView子类。它使用另一个 UILabel显示占位符,当文本为空时显示。

其他回答

下面是swift 3.1的代码

原始代码由杰森乔治在第一个答案。

不要忘记设置你的自定义类的TextView在接口生成器UIPlaceHolderTextView,然后设置占位符和占位符属性。

import UIKit

@IBDesignable
class UIPlaceHolderTextView: UITextView {

@IBInspectable var placeholder: String = ""
@IBInspectable var placeholderColor: UIColor = UIColor.lightGray

private let uiPlaceholderTextChangedAnimationDuration: Double = 0.05
private let defaultTagValue = 999

private var placeHolderLabel: UILabel?

override func awakeFromNib() {
    super.awakeFromNib()
    NotificationCenter.default.addObserver(
        self,
        selector: #selector(textChanged),
        name: NSNotification.Name.UITextViewTextDidChange,
        object: nil
    )
}

override init(frame: CGRect, textContainer: NSTextContainer?) {
    super.init(frame: frame, textContainer: textContainer)
    NotificationCenter.default.addObserver(
        self,
        selector: #selector(textChanged),
        name: NSNotification.Name.UITextViewTextDidChange,
        object: nil
    )
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    NotificationCenter.default.addObserver(
        self,
        selector: #selector(textChanged),
        name: NSNotification.Name.UITextViewTextDidChange,
        object: nil
    )
}

deinit {
    NotificationCenter.default.removeObserver(
        self,
        name: NSNotification.Name.UITextViewTextDidChange,
        object: nil
    )
}

@objc private func textChanged() {
    guard !placeholder.isEmpty else {
        return
    }
    UIView.animate(withDuration: uiPlaceholderTextChangedAnimationDuration) {
        if self.text.isEmpty {
            self.viewWithTag(self.defaultTagValue)?.alpha = CGFloat(1.0)
        }
        else {
            self.viewWithTag(self.defaultTagValue)?.alpha = CGFloat(0.0)
        }
    }
}

override var text: String! {
    didSet{
        super.text = text
        textChanged()
    }
}

override func draw(_ rect: CGRect) {
    if !placeholder.isEmpty {
        if placeHolderLabel == nil {
            placeHolderLabel = UILabel.init(frame: CGRect(x: 0, y: 8, width: bounds.size.width - 16, height: 0))
            placeHolderLabel!.lineBreakMode = .byWordWrapping
            placeHolderLabel!.numberOfLines = 0
            placeHolderLabel!.font = font
            placeHolderLabel!.backgroundColor = UIColor.clear
            placeHolderLabel!.textColor = placeholderColor
            placeHolderLabel!.alpha = 0
            placeHolderLabel!.tag = defaultTagValue
            self.addSubview(placeHolderLabel!)
        }

        placeHolderLabel!.text = placeholder
        placeHolderLabel!.sizeToFit()
        self.sendSubview(toBack: placeHolderLabel!)

        if text.isEmpty && !placeholder.isEmpty {
            viewWithTag(defaultTagValue)?.alpha = 1.0
        }
    }

    super.draw(rect)
}
}

你也可以创建一个新的类TextViewWithPlaceholder作为UITextView的子类。

(这段代码有点粗糙——但我认为它在正确的轨道上。)

@interface TextViewWithPlaceholder : UITextView
{

    NSString *placeholderText;  // make a property
    UIColor *placeholderColor;  // make a property
    UIColor *normalTextColor;   // cache text color here whenever you switch to the placeholderColor
}

- (void) setTextColor: (UIColor*) color
{
   normalTextColor = color;
   [super setTextColor: color];
}

- (void) updateForTextChange
{
    if ([self.text length] == 0)
    { 
        normalTextColor = self.textColor;
        self.textColor = placeholderColor;
        self.text = placeholderText;
    }
    else
    {
        self.textColor = normalTextColor;
    }

}

在委托中,添加以下内容:

- (void)textViewDidChange:(UITextView *)textView
{
    if ([textView respondsToSelector: @selector(updateForTextChange)])
    {
        [textView updateForTextChange];
    }

}

首先在.h文件中取一个标签。

这里我取

UILabel * lbl;

然后在。m中viewDidLoad下声明它

lbl = [[UILabel alloc] initWithFrame:CGRectMake(8.0, 0.0,250, 34.0)];

lbl.font=[UIFont systemFontOfSize:14.0];

[lbl setText:@"Write a message..."];

[lbl setBackgroundColor:[UIColor clearColor]];

[lbl setTextColor:[UIColor lightGrayColor]];

[textview addSubview:lbl];

textview是我的textview。

现在声明

-(void)textViewDidChange:(UITextView *)textView {

 if (![textView hasText]){

    lbl.hidden = NO;

 }
 else{
    lbl.hidden = YES;
 }

}

和你的Textview占位符准备好了!

如果你正在寻找一个简单的方法来实现这一点,试试我的方法:

- (BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
    if ([[textView text] isEqualToString:PLACE_HOLDER_TEXT]) {
          textView.text = @"";
          textView.textColor = [UIColor blackColor];
    }

    return YES;
}

-(BOOL)textViewShouldEndEditing:(UITextView *)textView
{
    if ([[textView text] length] == 0) {
        textView.text = PLACE_HOLDER_TEXT;
        textView.textColor = [UIColor lightGrayColor];
    }
    return YES;
}

是的,就是它PLACE_HOLDER_TEXT是一个NSString包含你的占位符

TextView占位符

import UIKit

@IBDesignable
open class KMPlaceholderTextView: UITextView {

    private struct Constants {
        static let defaultiOSPlaceholderColor = UIColor(red: 0.0, green: 0.0, blue: 0.0980392, alpha: 0.22)
    }

    public let placeholderLabel: UILabel = UILabel()

    private var placeholderLabelConstraints = [NSLayoutConstraint]()

    @IBInspectable open var placeholder: String = "" {
        didSet {
            placeholderLabel.text = placeholder
        }
    }

    @IBInspectable open var placeholderColor: UIColor = KMPlaceholderTextView.Constants.defaultiOSPlaceholderColor {
        didSet {
            placeholderLabel.textColor = placeholderColor
        }
    }

    override open var font: UIFont! {
        didSet {
            if placeholderFont == nil {
                placeholderLabel.font = font
            }
        }
    }

    open var placeholderFont: UIFont? {
        didSet {
            let font = (placeholderFont != nil) ? placeholderFont : self.font
            placeholderLabel.font = font
        }
    }

    override open var textAlignment: NSTextAlignment {
        didSet {
            placeholderLabel.textAlignment = textAlignment
        }
    }

    override open var text: String! {
        didSet {
            textDidChange()
        }
    }

    override open var attributedText: NSAttributedString! {
        didSet {
            textDidChange()
        }
    }

    override open var textContainerInset: UIEdgeInsets {
        didSet {
            updateConstraintsForPlaceholderLabel()
        }
    }

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

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

    private func commonInit() {
        #if swift(>=4.2)
        let notificationName = UITextView.textDidChangeNotification
        #else
        let notificationName = NSNotification.Name.UITextView.textDidChangeNotification
        #endif

        NotificationCenter.default.addObserver(self,
                                               selector: #selector(textDidChange),
                                               name: notificationName,
                                               object: nil)

        placeholderLabel.font = font
        placeholderLabel.textColor = placeholderColor
        placeholderLabel.textAlignment = textAlignment
        placeholderLabel.text = placeholder
        placeholderLabel.numberOfLines = 0
        placeholderLabel.backgroundColor = UIColor.clear
        placeholderLabel.translatesAutoresizingMaskIntoConstraints = false
        addSubview(placeholderLabel)
        updateConstraintsForPlaceholderLabel()
    }

    private func updateConstraintsForPlaceholderLabel() {
        var newConstraints = NSLayoutConstraint.constraints(withVisualFormat: "H:|-(\(textContainerInset.left + textContainer.lineFragmentPadding))-[placeholder]",
            options: [],
            metrics: nil,
            views: ["placeholder": placeholderLabel])
        newConstraints += NSLayoutConstraint.constraints(withVisualFormat: "V:|-(\(textContainerInset.top))-[placeholder]",
            options: [],
            metrics: nil,
            views: ["placeholder": placeholderLabel])
        newConstraints.append(NSLayoutConstraint(
            item: placeholderLabel,
            attribute: .width,
            relatedBy: .equal,
            toItem: self,
            attribute: .width,
            multiplier: 1.0,
            constant: -(textContainerInset.left + textContainerInset.right + textContainer.lineFragmentPadding * 2.0)
        ))
        removeConstraints(placeholderLabelConstraints)
        addConstraints(newConstraints)
        placeholderLabelConstraints = newConstraints
    }

    @objc private func textDidChange() {
        placeholderLabel.isHidden = !text.isEmpty
        self.layoutIfNeeded()
    }

    open override func layoutSubviews() {
        super.layoutSubviews()
        placeholderLabel.preferredMaxLayoutWidth = textContainer.size.width - textContainer.lineFragmentPadding * 2.0
    }

    deinit {
        #if swift(>=4.2)
        let notificationName = UITextView.textDidChangeNotification
        #else
        let notificationName = NSNotification.Name.UITextView.textDidChangeNotification
        #endif

        NotificationCenter.default.removeObserver(self,
                                                  name: notificationName,
                                                  object: nil)
    }

}

使用