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

如何做到这一点?


当前回答

- (void)viewDidLoad {
    [super viewDidLoad];

    self.textViewEmpty = YES;

    // Text view
    self.textView = [[UITextView alloc] init];
    self.textView.translatesAutoresizingMaskIntoConstraints = NO; // For AutoLayout
    self.textView.delegate = self;
    self.textView.textColor = [UIColor grayColor];
    self.textView.text = @"Placeholder";

    // Add subview and constraints
}

#pragma mark - UITextView

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

    return YES;
}

- (void)textViewDidChange:(UITextView *)textView {
    if (textView.text.length > 0) {
        self.textViewEmpty = NO;
    } else {
        self.textViewEmpty = YES;
    }
}

- (BOOL)textViewShouldEndEditing:(UITextView *)textView {
    if (self.isTextViewEmpty) {
        textView.textColor = [UIColor lightGrayColor];
        textView.text = placeholderText;
    }

    return YES;
}

其他回答

我能够做添加一个“占位符”到UITextView与很多少的代码。这就是我所做的:

UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(60, 800, 200, 60)];
textView.text = @"Write characters here...";
textView.textColor=[UIColor grayColor];
textView.font = [UIFont fontWithName:@"Hevlatica" size:15];
textView.delegate=self;

我猜这不是一个真正的占位符,因为你必须在写之前删除文本,但如果你想要一些更简单的东西,它可能会有帮助。

好吧,我的阴沟有点不同 我创建了一个小班来为你做这件事。

TextViewShader。m文件

#import "TextViewShader.h"

@implementation TextViewShader
-(id)initWithShadedTextView:(NSString *)text textViewToShade:(UITextView *)textview {
    self = [super initWithFrame:textview.frame];
    if (self) {
        if (shadeLabel==nil)
        {
            shadeLabel= [[UILabel alloc]initWithFrame:CGRectMake(10, 0, textview.frame.size.width, 30)];


    }
    shadeLabel.text =text;// @"Enter Your Support Request";
    shadeLabel.textColor = [UIColor lightGrayColor];
    [textview setDelegate: self];
    [textview addSubview:shadeLabel];
}
return self;
}

-(void)textViewDidChange:(UITextView *)textView{
        if (textView.text.length==0)
        {
            shadeLabel.hidden=false; 
        }
        else
        {
            shadeLabel.hidden=true;
        }

}

@end

TextViewShader.h文件

#import <UIKit/UIKit.h>

@interface TextViewShader : UIView<UITextViewDelegate>{
    UILabel *shadeLabel;

}
-(id)initWithShadedTextView:(NSString *)text textViewToShade:(UITextView *)textview ;
@end

这是简单的一行代码使用(不要忘记添加#import "TextViewShader.h")

 TextViewShader* shader = [[TextViewShader alloc]initWithShadedTextView:@"Enter Your Support Request" textViewToShade: youruitextviewToshade];

玩得开心!

我对发布的任何解决方案都不太满意,因为它们有点重。向视图中添加视图并不理想(尤其是在drawRect:)。它们都有漏洞,这也是不可接受的。

这是我的解决方案:SAMTextView

SAMTextView.h

//
//  SAMTextView.h
//  SAMTextView
//
//  Created by Sam Soffes on 8/18/10.
//  Copyright 2010-2013 Sam Soffes. All rights reserved.
//

#import <UIKit/UIKit.h>

/**
 UITextView subclass that adds placeholder support like UITextField has.
 */
@interface SAMTextView : UITextView

/**
 The string that is displayed when there is no other text in the text view.

 The default value is `nil`.
 */
@property (nonatomic, strong) NSString *placeholder;

/**
 The color of the placeholder.

 The default is `[UIColor lightGrayColor]`.
 */
@property (nonatomic, strong) UIColor *placeholderTextColor;

/**
 Returns the drawing rectangle for the text views’s placeholder text.

 @param bounds The bounding rectangle of the receiver.
 @return The computed drawing rectangle for the placeholder text.
 */
- (CGRect)placeholderRectForBounds:(CGRect)bounds;

@end

SAMTextView.m

//
//  SAMTextView.m
//  SAMTextView
//
//  Created by Sam Soffes on 8/18/10.
//  Copyright 2010-2013 Sam Soffes. All rights reserved.
//

#import "SAMTextView.h"

@implementation SAMTextView

#pragma mark - Accessors

@synthesize placeholder = _placeholder;
@synthesize placeholderTextColor = _placeholderTextColor;

- (void)setText:(NSString *)string {
  [super setText:string];
  [self setNeedsDisplay];
}


- (void)insertText:(NSString *)string {
  [super insertText:string];
  [self setNeedsDisplay];
}


- (void)setAttributedText:(NSAttributedString *)attributedText {
  [super setAttributedText:attributedText];
  [self setNeedsDisplay];
}


- (void)setPlaceholder:(NSString *)string {
  if ([string isEqual:_placeholder]) {
    return;
  }

  _placeholder = string;
  [self setNeedsDisplay];
}


- (void)setContentInset:(UIEdgeInsets)contentInset {
  [super setContentInset:contentInset];
  [self setNeedsDisplay];
}


- (void)setFont:(UIFont *)font {
  [super setFont:font];
  [self setNeedsDisplay];
}


- (void)setTextAlignment:(NSTextAlignment)textAlignment {
  [super setTextAlignment:textAlignment];
  [self setNeedsDisplay];
}


#pragma mark - NSObject

- (void)dealloc {
  [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextViewTextDidChangeNotification object:self];
}


#pragma mark - UIView

- (id)initWithCoder:(NSCoder *)aDecoder {
  if ((self = [super initWithCoder:aDecoder])) {
    [self initialize];
  }
  return self;
}


- (id)initWithFrame:(CGRect)frame {
  if ((self = [super initWithFrame:frame])) {
    [self initialize];
  }
  return self;
}


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

  if (self.text.length == 0 && self.placeholder) {
    rect = [self placeholderRectForBounds:self.bounds];

    UIFont *font = self.font ? self.font : self.typingAttributes[NSFontAttributeName];

    // Draw the text
    [self.placeholderTextColor set];
    [self.placeholder drawInRect:rect withFont:font lineBreakMode:NSLineBreakByTruncatingTail alignment:self.textAlignment];
  }
}


#pragma mark - Placeholder

- (CGRect)placeholderRectForBounds:(CGRect)bounds {
  // Inset the rect
  CGRect rect = UIEdgeInsetsInsetRect(bounds, self.contentInset);

  if (self.typingAttributes) {
    NSParagraphStyle *style = self.typingAttributes[NSParagraphStyleAttributeName];
    if (style) {
      rect.origin.x += style.headIndent;
      rect.origin.y += style.firstLineHeadIndent;
    }
  }

  return rect;
}


#pragma mark - Private

- (void)initialize {
  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChanged:) name:UITextViewTextDidChangeNotification object:self];

  self.placeholderTextColor = [UIColor colorWithWhite:0.702f alpha:1.0f];
}


- (void)textChanged:(NSNotification *)notification {
  [self setNeedsDisplay];
}

@end

它比其他的要简单得多,因为它不使用子视图(或有泄漏)。请随意使用。

更新11/10/11:它现在是文档化的,并支持在接口生成器中使用。

更新11/24/13:指向新的回购。

我已经创建了一个快速3版本的最高排名的答案

你只需要做UITextView的子类化。

import UIKit

 class UIPlaceHolderTextView: UITextView {


//MARK: - Properties
@IBInspectable var placeholder: String?
@IBInspectable var placeholderColor: UIColor?
var placeholderLabel: UILabel?


//MARK: - Initializers
override func awakeFromNib() {
    super.awakeFromNib()


}

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

    // Use Interface Builder User Defined Runtime Attributes to set
    // placeholder and placeholderColor in Interface Builder.
    if self.placeholder == nil {
        self.placeholder = ""
    }

    if self.placeholderColor == nil {
        self.placeholderColor = UIColor.black
    }

    NotificationCenter.default.addObserver(self, selector: #selector(textChanged(_:)), name: NSNotification.Name.UITextViewTextDidChange, object: nil)

}

func textChanged(_ notification: Notification) -> Void {
    if self.placeholder?.count == 0 {
        return
    }

    UIView.animate(withDuration: 0.25) {
        if self.text.count == 0 {
            self.viewWithTag(999)?.alpha = 1
        }
        else {
            self.viewWithTag(999)?.alpha = 0
        }
    }
}

// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {
    super.draw(rect)

    if (self.placeholder?.count ?? 0) > 0 {
        if placeholderLabel == nil {
            placeholderLabel = UILabel.init()
            placeholderLabel?.lineBreakMode = .byWordWrapping
            placeholderLabel?.numberOfLines = 0
            placeholderLabel?.font = self.font
            placeholderLabel?.backgroundColor = self.backgroundColor
            placeholderLabel?.textColor = self.placeholderColor
            placeholderLabel?.alpha = 0
            placeholderLabel?.tag = 999
            self.addSubview(placeholderLabel!)

            placeholderLabel?.translatesAutoresizingMaskIntoConstraints = false
            placeholderLabel?.topAnchor.constraint(equalTo: self.topAnchor, constant: 7).isActive = true
            placeholderLabel?.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 4).isActive = true
            placeholderLabel?.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
            placeholderLabel?.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
        }

        placeholderLabel?.text = self.placeholder
        placeholderLabel?.sizeToFit()
        self.sendSubview(toBack: self.placeholderLabel!)
    }

    if self.text.count == 0 && (self.placeholder?.count ?? 0) > 0 {
        self.viewWithTag(999)?.alpha = 1
    }
 }
}

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

它扩展了现有的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…)