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

如何做到这一点?


当前回答

在代码行中使用它的简单方法:

取一个标签到。nib中的UITextView 将这个标签连接到你的代码, 在它。

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{

    if (range.location>0 || text.length!=0) {
        placeholderLabel1.hidden = YES;
    }else{
        placeholderLabel1.hidden = NO;
    }
    return YES;
}

其他回答

在swift 5。工作很好。

class BaseTextView: UITextView {

    // MARK: - Views
    private var placeholderLabel: UIlabel!

    // MARK: - Init
    override init(frame: CGRect, textContainer: NSTextContainer?) {
        super.init(frame: frame, textContainer: textContainer)
        setupUI()
        startupSetup()
    }

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

    deinit {
        NotificationCenter.default.removeObserver(self)
    }    
}

// MARK: - Setup UI
private extension BaseTextView {
    func setupUI() {
        addPlaceholderLabel()

        textColor = .textColor
    }

    func addPlaceholderLabel() {
        placeholderLabel = BaseLabel(frame: .zero)
        placeholderLabel.translatesAutoresizingMaskIntoConstraints = false
        insertSubview(placeholderLabel, at: 0)

        placeholderLabel.alpha = 0
        placeholderLabel.numberOfLines = 0
        placeholderLabel.backgroundColor = .clear
        placeholderLabel.textColor = .lightTextColor
        placeholderLabel.lineBreakMode = .byWordWrapping
        placeholderLabel.isUserInteractionEnabled = false
        placeholderLabel.font = UIFont.openSansSemibold.withSize(12)

        placeholderLabel.topAnchor.constraint(equalTo: topAnchor, constant: 8).isActive = true
        placeholderLabel.leftAnchor.constraint(equalTo: leftAnchor, constant: 5).isActive = true
        placeholderLabel.rightAnchor.constraint(lessThanOrEqualTo: rightAnchor, constant: -8).isActive = true
        placeholderLabel.bottomAnchor.constraint(lessThanOrEqualTo: bottomAnchor, constant: -8).isActive = true
    }
}

// MARK: - Startup
private extension BaseTextView {
    func startupSetup() {
        addObservers()
        textChanged(nil)
        font = UIFont.openSansSemibold.withSize(12)
    }    

    func addObservers() {
        NotificationCenter.default.addObserver(self, selector: #selector(textChanged(_:)), name: UITextView.textDidChangeNotification, object: nil)
    }
}

// MARK: - Actions
private extension BaseTextView {
    @objc func textChanged(_ sender: Notification?) {
        UIView.animate(withDuration: 0.2) {
            self.placeholderLabel.alpha = self.text.count == 0 ? 1 : 0
        }    
    }
}

// MARK: - Public methods
extension BaseTextView {
    public func setPlaceholder(_ placeholder: String) {
        placeholderLabel.text = placeholder
    }
}

这个帖子已经有了很多答案,但这里是我更喜欢的版本。

它扩展了现有的UITextView类,因此很容易重用,并且它不拦截像textViewDidChange这样的事件(这可能会破坏用户的代码,如果他们已经在其他地方拦截了这些事件)。

使用我的代码(如下所示),你可以很容易地添加一个占位符到任何你的UITextViews像这样:

self.textViewComments.placeholder = @"(Enter some comments here.)";

当你设置这个新的占位符值时,它会悄悄地在你的UITextView上添加一个UILabel,然后在必要时隐藏/显示它:

好的,要做这些改变,添加一个包含以下代码的"UITextViewHelper.h"文件:

//  UITextViewHelper.h
//  Created by Michael Gledhill on 13/02/15.

#import <Foundation/Foundation.h>

@interface UITextView (UITextViewHelper)

@property (nonatomic, strong) NSString* placeholder;
@property (nonatomic, strong) UILabel* placeholderLabel;
@property (nonatomic, strong) NSString* textValue;

-(void)checkIfNeedToDisplayPlaceholder;

@end

…和一个UITextViewHelper。M文件包含:

//  UITextViewHelper.m
//  Created by Michael Gledhill on 13/02/15.
//
//  This UITextView category allows us to easily display a PlaceHolder string in our UITextView.
//  The downside is that, your code needs to set the "textValue" rather than the "text" value to safely set the UITextView's text.
//
#import "UITextViewHelper.h"
#import <objc/runtime.h>

@implementation UITextView (UITextViewHelper)

#define UI_PLACEHOLDER_TEXT_COLOR [UIColor colorWithRed:170.0/255.0 green:170.0/255.0 blue:170.0/255.0 alpha:1.0]

@dynamic placeholder;
@dynamic placeholderLabel;
@dynamic textValue;

-(void)setTextValue:(NSString *)textValue
{
    //  Change the text of our UITextView, and check whether we need to display the placeholder.
    self.text = textValue;
    [self checkIfNeedToDisplayPlaceholder];
}
-(NSString*)textValue
{
    return self.text;
}

-(void)checkIfNeedToDisplayPlaceholder
{
    //  If our UITextView is empty, display our Placeholder label (if we have one)
    if (self.placeholderLabel == nil)
        return;

    self.placeholderLabel.hidden = (![self.text isEqualToString:@""]);
}

-(void)onTap
{
    //  When the user taps in our UITextView, we'll see if we need to remove the placeholder text.
    [self checkIfNeedToDisplayPlaceholder];

    //  Make the onscreen keyboard appear.
    [self becomeFirstResponder];
}

-(void)keyPressed:(NSNotification*)notification
{
    //  The user has just typed a character in our UITextView (or pressed the delete key).
    //  Do we need to display our Placeholder label ?
   [self checkIfNeedToDisplayPlaceholder];
}

#pragma mark - Add a "placeHolder" string to the UITextView class

NSString const *kKeyPlaceHolder = @"kKeyPlaceHolder";
-(void)setPlaceholder:(NSString *)_placeholder
{
    //  Sets our "placeholder" text string, creates a new UILabel to contain it, and modifies our UITextView to cope with
    //  showing/hiding the UILabel when needed.
    objc_setAssociatedObject(self, &kKeyPlaceHolder, (id)_placeholder, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

    self.placeholderLabel = [[UILabel alloc] initWithFrame:self.frame];
    self.placeholderLabel.numberOfLines = 1;
    self.placeholderLabel.text = _placeholder;
    self.placeholderLabel.textColor = UI_PLACEHOLDER_TEXT_COLOR;
    self.placeholderLabel.backgroundColor = [UIColor clearColor];
    self.placeholderLabel.userInteractionEnabled = true;
    self.placeholderLabel.font = self.font;
    [self addSubview:self.placeholderLabel];

    [self.placeholderLabel sizeToFit];

    //  Whenever the user taps within the UITextView, we'll give the textview the focus, and hide the placeholder if necessary.
    [self addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTap)]];

    //  Whenever the user types something in the UITextView, we'll see if we need to hide/show the placeholder label.
    [[NSNotificationCenter defaultCenter] addObserver:self selector: @selector(keyPressed:) name:UITextViewTextDidChangeNotification object:nil];

    [self checkIfNeedToDisplayPlaceholder];
}
-(NSString*)placeholder
{
    //  Returns our "placeholder" text string
    return objc_getAssociatedObject(self, &kKeyPlaceHolder);
}

#pragma mark - Add a "UILabel" to this UITextView class

NSString const *kKeyLabel = @"kKeyLabel";
-(void)setPlaceholderLabel:(UILabel *)placeholderLabel
{
    //  Stores our new UILabel (which contains our placeholder string)
    objc_setAssociatedObject(self, &kKeyLabel, (id)placeholderLabel, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

    [[NSNotificationCenter defaultCenter] addObserver:self selector: @selector(keyPressed:) name:UITextViewTextDidChangeNotification object:nil];

    [self checkIfNeedToDisplayPlaceholder];
}
-(UILabel*)placeholderLabel
{
    //  Returns our new UILabel
    return objc_getAssociatedObject(self, &kKeyLabel);
}
@end

是的,它有很多代码,但是一旦你把它添加到你的项目中,并包含了.h文件……

#import "UITextViewHelper.h"

...你可以很容易地在UITextViews中使用占位符。

不过有一个问题。

如果你这样做:

self.textViewComments.placeholder = @"(Enter some comments here.)";
self.textViewComments.text = @"Ooooh, hello there";

...占位符将出现在文本的顶部。设置文本值时,不会调用任何常规通知,因此我不知道如何调用我的函数来决定是否显示/隐藏占位符。

解决方案是设置textValue而不是text:

self.textViewComments.placeholder = @"(Enter some comments here.)";
self.textViewComments.textValue = @"Ooooh, hello there";

或者,您可以设置文本值,然后调用checkIfNeedToDisplayPlaceholder。

self.textViewComments.text = @"Ooooh, hello there";
[self.textViewComments checkIfNeedToDisplayPlaceholder];

我喜欢这样的解决方案,因为它们“填补了”苹果提供给我们的东西和我们(作为开发者)在应用程序中实际需要的东西之间的空白。只需编写一次此代码,将其添加到“helper”.m/.h文件库中,随着时间的推移,SDK实际上开始变得不那么令人沮丧。

(我写了一个类似的帮助添加一个“清除”按钮到我的UITextViews,另一个烦人的东西存在于UITextField但不在UITextView…)

- (BOOL) textViewShouldBeginEditing:(UITextView *)textView
{
    //NSLog(@"textViewShouldBeginEditing");
    if( [tvComment.text isEqualToString:@"Comment"] && [tvComment.textColor isEqual:[UIColor lightGrayColor]] ){
        tvComment.text = @"";
        tvComment.textColor = [UIColor blackColor];
    }
    return YES;
}

- (void)keyboardWillBeHidden:(NSNotification*)aNotification{
    //NSLog(@"keyboardWillBeHidden");

    //Manage comment field placeholdertext
    if(tvComment.text.length == 0){
        tvComment.textColor = [UIColor lightGrayColor];
        tvComment.text = @"Comment";
    }
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    tvComment.textColor = [UIColor lightGrayColor];
}

TVComment是包含问题中的textView的属性。这样就可以了。

我建议使用pod 'UITextView+Placeholder'

pod 'UITextView+Placeholder'

在代码中

#import "UITextView+Placeholder.h"

////    

UITextView *textView = [[UITextView alloc] init];
textView.placeholder = @"How are you?";
textView.placeholderColor = [UIColor lightGrayColor];

简单的方法,使用以下UITextViewDelegate方法在UITextView中创建占位符文本:

- (void)textViewDidBeginEditing:(UITextView *)textView
{
    if ([textView.text isEqualToString:@"placeholder text here..."]) {
         textView.text = @"";
         textView.textColor = [UIColor blackColor]; //optional
    }
    [textView becomeFirstResponder];
}

- (void)textViewDidEndEditing:(UITextView *)textView
{
    if ([textView.text isEqualToString:@""]) {
        textView.text = @"placeholder text here...";
        textView.textColor = [UIColor lightGrayColor]; //optional
    }
    [textView resignFirstResponder];
}

只需要记住在创建时使用准确的文本设置myUITextView即可。

UITextView *myUITextView = [[UITextView alloc] init];
myUITextView.delegate = self;
myUITextView.text = @"placeholder text here...";
myUITextView.textColor = [UIColor lightGrayColor]; //optional

在包含这些方法之前,让父类成为一个UITextViewDelegate。

@interface MyClass () <UITextViewDelegate>
@end

Swift 3.1代码

func textViewDidBeginEditing(_ textView: UITextView) 
{
    if (textView.text == "placeholder text here..." && textView.textColor == .lightGray)
    {
        textView.text = ""
        textView.textColor = .black
    }
    textView.becomeFirstResponder() //Optional
}

func textViewDidEndEditing(_ textView: UITextView)
{
    if (textView.text == "")
    {
        textView.text = "placeholder text here..."
        textView.textColor = .lightGray
    }
    textView.resignFirstResponder()
}

只需要记住在创建时使用准确的文本设置myUITextView即可。

 let myUITextView = UITextView.init()
 myUITextView.delegate = self
 myUITextView.text = "placeholder text here..."
 myUITextView.textColor = .lightGray

在包含这些方法之前,让父类成为一个UITextViewDelegate。

class MyClass: UITextViewDelegate
{

}