UITextView中的占位符

我的应用程序使用UITextView。现在我希望UITextView有一个类似于您可以为UITextField设置的占位符。

这要怎么做?

388861 次浏览

你可以做的是在text属性中设置具有某些初始值的文本视图,并将textColor更改为[UIColor grayColor]或类似的内容。然后,每当文本视图变得可编辑时,清除文本并显示光标,如果文本字段再次为空,则将占位符文本放回原处。根据需要将颜色更改为[UIColor blackColor]

它与UITextField中的占位符功能不完全相同,但它很接近。

您还可以创建一个新的类TextViewWith Place持有人作为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];
}


}

我是这样做的:

UITextView2. h接口说明

#import <UIKit/UIKit.h>


@interface UITextView2 : UITextView <UITextViewDelegate> {
NSString *placeholder;
UIColor *placeholderColor;
}


@property(nonatomic, retain) NSString *placeholder;
@property(nonatomic, retain) UIColor *placeholderColor;


-(void)textChanged:(NSNotification*)notif;


@end

UI文本视图2.m

@implementation UITextView2


@synthesize placeholder, placeholderColor;


- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self setPlaceholder:@""];
[self setPlaceholderColor:[UIColor lightGrayColor]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChanged:) name:UITextViewTextDidChangeNotification object:nil];
}
return self;
}


-(void)textChanged:(NSNotification*)notif {
if ([[self placeholder] length]==0)
return;
if ([[self text] length]==0) {
[[self viewWithTag:999] setAlpha:1];
} else {
[[self viewWithTag:999] setAlpha:0];
}


}


- (void)drawRect:(CGRect)rect {
if ([[self placeholder] length]>0) {
UILabel *l = [[UILabel alloc] initWithFrame:CGRectMake(8, 8, 0, 0)];
[l setFont:self.font];
[l setTextColor:self.placeholderColor];
[l setText:self.placeholder];
[l setAlpha:0];
[l setTag:999];
[self addSubview:l];
[l sizeToFit];
[self sendSubviewToBack:l];
[l release];
}
if ([[self text] length]==0 && [[self placeholder] length]>0) {
[[self viewWithTag:999] setAlpha:1];
}
[super drawRect:rect];
}


- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}




@end

我对bcd的解决方案做了一些小的修改,以允许从Xib文件初始化、文本包装和保持背景颜色。希望它能省去其他人的麻烦。

UI PlaceHolder Text View. h:

#import <Foundation/Foundation.h>
IB_DESIGNABLE
@interface UIPlaceHolderTextView : UITextView


@property (nonatomic, retain) IBInspectable NSString *placeholder;
@property (nonatomic, retain) IBInspectable UIColor *placeholderColor;


-(void)textChanged:(NSNotification*)notification;


@end

UI PlaceHolder Text View. m:

#import "UIPlaceHolderTextView.h"


@interface UIPlaceHolderTextView ()


@property (nonatomic, retain) UILabel *placeHolderLabel;


@end


@implementation UIPlaceHolderTextView


CGFloat const UI_PLACEHOLDER_TEXT_CHANGED_ANIMATION_DURATION = 0.25;


- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
#if __has_feature(objc_arc)
#else
[_placeHolderLabel release]; _placeHolderLabel = nil;
[_placeholderColor release]; _placeholderColor = nil;
[_placeholder release]; _placeholder = nil;
[super dealloc];
#endif
}


- (void)awakeFromNib
{
[super awakeFromNib];


    // Use Interface Builder User Defined Runtime Attributes to set
    // placeholder and placeholderColor in Interface Builder.
if (!self.placeholder) {
[self setPlaceholder:@""];
}


if (!self.placeholderColor) {
[self setPlaceholderColor:[UIColor lightGrayColor]];
}


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


- (id)initWithFrame:(CGRect)frame
{
if( (self = [super initWithFrame:frame]) )
{
[self setPlaceholder:@""];
[self setPlaceholderColor:[UIColor lightGrayColor]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChanged:) name:UITextViewTextDidChangeNotification object:nil];
}
return self;
}


- (void)textChanged:(NSNotification *)notification
{
if([[self placeholder] length] == 0)
{
return;
}


[UIView animateWithDuration:UI_PLACEHOLDER_TEXT_CHANGED_ANIMATION_DURATION animations:^{
if([[self text] length] == 0)
{
[[self viewWithTag:999] setAlpha:1];
}
else
{
[[self viewWithTag:999] setAlpha:0];
}
}];
}


- (void)setText:(NSString *)text {
[super setText:text];
[self textChanged:nil];
}


- (void)drawRect:(CGRect)rect
{
if( [[self placeholder] length] > 0 )
{
if (_placeHolderLabel == nil )
{
_placeHolderLabel = [[UILabel alloc] initWithFrame:CGRectMake(8,8,self.bounds.size.width - 16,0)];
_placeHolderLabel.lineBreakMode = NSLineBreakByWordWrapping;
_placeHolderLabel.numberOfLines = 0;
_placeHolderLabel.font = self.font;
_placeHolderLabel.backgroundColor = [UIColor clearColor];
_placeHolderLabel.textColor = self.placeholderColor;
_placeHolderLabel.alpha = 0;
_placeHolderLabel.tag = 999;
[self addSubview:_placeHolderLabel];
}


_placeHolderLabel.text = self.placeholder;
[_placeHolderLabel sizeToFit];
[self sendSubviewToBack:_placeHolderLabel];
}


if( [[self text] length] == 0 && [[self placeholder] length] > 0 )
{
[[self viewWithTag:999] setAlpha:1];
}


[super drawRect:rect];
}


@end

您可以通过以下方式在UITextView上设置标签

[UITextView addSubView:lblPlaceHoldaer];

并将其隐藏在TextViewdidChange方法上。

这是简单和容易的方法。

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

这是我的解决方案:文本视图

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更新:现在已记录并支持在Interface Builder中使用。

更新11/24/13:指向新的仓库。

我制作了我自己的UITextView子类版本。我喜欢萨姆·索菲斯使用通知的想法,但我不喜欢DraRect:覆盖。对我来说似乎有些矫枉过正。我认为我做了一个非常干净的实现。

您可以查看我的子类这里。还包括一个演示项目。

我创建了一个实例变量来检查是否显示占位符:

BOOL showPlaceHolder;
UITextView * textView; // and also the textView

我设置了一个视图:

[self setPlaceHolder];

这就是它的作用:

- (void)setPlaceholder
{
textView.text = NSLocalizedString(@"Type your question here", @"placeholder");
textView.textColor = [UIColor lightGrayColor];
self.showPlaceHolder = YES; //we save the state so it won't disappear in case you want to re-edit it
}

我还创建了一个按钮来退出键盘。你不必这样做,但这里很酷的是,如果没有输入任何内容,占位符会再次显示

- (void)textViewDidBeginEditing:(UITextView *)txtView
{
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(resignKeyboard)];
if (self.showPlaceHolder == YES)
{
textView.textColor = [UIColor blackColor];
textView.text = @"";
self.showPlaceHolder = NO;
}
}


- (void)resignKeyboard
{
[textView resignFirstResponder];
//here if you created a button like I did to resign the keyboard, you should hide it
if (textView.text.length == 0) {
[self setPlaceholder];
}
}

我发现自己很容易就能模仿一个占位者

  1. 在NIB或代码中,将文本视图的文本颜色设置为light GrayColor(大多数时候)
  2. 确保您的text View的委托链接到文件的所有者并在您的头文件中实现UITextView委托
  3. 将文本视图的默认文本设置为(例如:“页脚占位符”)
  4. UITextView: UITextView*//文本视图的实现方式

编辑:

将if语句更改为比较标签而不是文本。如果用户删除了他们的文本,也有可能意外删除占位符的一部分@"Foobar placeholder"。这意味着如果用户重新输入text View以下委托方法-(BOOL) textViewShouldBeginEditing:(UITextView *) textView,它将无法按预期工作。我尝试通过if语句中文本的颜色进行比较,但发现界面生成器中设置的浅灰色与代码中设置的[UIColor lightGreyColor]中的浅灰色不同

- (BOOL) textViewShouldBeginEditing:(UITextView *)textView
{
if(textView.tag == 0) {
textView.text = @"";
textView.textColor = [UIColor blackColor];
textView.tag = 1;
}
return YES;
}

也可以在键盘返回时重置占位符文本,并且[text View长度]==0

编辑:

只是为了使最后一部分更清晰-这是如何设置占位符文本:

- (void)textViewDidChange:(UITextView *)textView
{
if([textView.text length] == 0)
{
textView.text = @"Foobar placeholder";
textView.textColor = [UIColor lightGrayColor];
textView.tag = 0;
}
}

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

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

这是简单的一行代码用法(不要忘记添加#甜心“TextViewShader. h”)

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

玩得开心:)

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

将一个标签带到. 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;
}

简单的方法,只需使用以下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
{


}
    - (void)textViewDidChange:(UITextView *)textView
{
placeholderLabel.hidden = YES;
}

在文本视图上放置一个标签。

这是另一种方法,它再现了UITextField占位符的轻微缩进:

UITextField拖到UITextView下方,使其左上角对齐。将占位符文本添加到文本字段。

在viewTitLoad中,添加:

[tView setDelegate:self];
tView.contentInset = UIEdgeInsetsMake(-8,-8,0,0);
tView.backgroundColor = [UIColor clearColor];

然后添加:

- (void)textViewDidChange:(UITextView *)textView {
if (textView.text.length == 0) {
textView.backgroundColor = [UIColor clearColor];
} else {
textView.backgroundColor = [UIColor whiteColor];
}
}

更简单,并且仍然占用户在某些时候输入的某些文本

BOOL placeHolderTextVisible;

在viewTitLoad上,将其设置为YES(或Di MoveToSuperview,或awakeFromNib)

然后,在 +(BOOL)text View: UITextView

是否需要编辑

    - (BOOL)textViewShouldBeginEditing:(UITextView *)textView;
{
if (placeHolderTextVisible) {
placeHolderTextVisible = NO;
textView.text = @"";
}
return YES;
}

这是一个更简单的解决方案,其行为与UITextField的占位符完全相同,但不需要绘制自定义视图或辞职第一响应者。

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


if (textView.text.length == 0){
textView.textColor = [UIColor lightGrayColor];
textView.text = placeholderText;
[textView setSelectedRange:NSMakeRange(0, 0)];
isPlaceholder = YES;


} else if (isPlaceholder && ![textView.text isEqualToString:placeholderText]) {
textView.text = [textView.text substringToIndex:1];
textView.textColor = [UIColor blackColor];
isPlaceholder = NO;
}


}

(其他if语句中的第二个检查是针对没有输入任何内容并且用户按退格的情况)

只需将您的类设置为UITextView就可以了。在视图中,您应该像这样初始化

- (void) viewDidLoad{
// initialize placeholder text
placeholderText = @"some placeholder";
isPlaceholder = YES;
self.someTextView.text = placeholderText;
self.someTextView.textColor = [UIColor lightGrayColor];
[self.someTextView setSelectedRange:NSMakeRange(0, 0)];


// assign UITextViewDelegate
self.someTextView.delegate = self;
}

让它变得简单

创建一个UILabel并将其放置在文本视图中(将文本设置为占位符-设置颜色灰色-您可以在xib中完成所有这些) 现在在你的头文件中声明UILabel和text view代表 现在你可以简单地隐藏标签,当你点击文本视图

下面的完整代码

报头

@interface ViewController :UIViewController<UITextViewDelegate>{
}
@property (nonatomic,strong) IBOutlet UILabel *PlceHolder_label;
@property (nonatomic,strong) IBOutlet UITextView *TextView;


@end

实施

@implementation UploadFoodImageViewController
@synthesize PlceHolder_label,TextView;


- (void)viewDidLoad
{
[super viewDidLoad];
}




- (BOOL)textViewShouldBeginEditing:(UITextView *)textView{


if([textView isEqual:TextView]){
[PlceHolder_label setHidden:YES];
[self.tabScrlVw setContentOffset:CGPointMake(0,150) animated:YES];
}
return YES;
}

@完

不要忘记从xib连接文本视图和UILabel到文件所有者

抱歉添加另一个答案,但我只是把这样的东西拉下来,这创建了最接近UITextField的占位符。

希望这有助于某人。

-(void)textViewDidChange:(UITextView *)textView{
if(textView.textColor == [UIColor lightGrayColor]){
textView.textColor  = [UIColor blackColor]; // look at the comment section in this answer
textView.text       = [textView.text substringToIndex: 0];// look at the comment section in this answer
}else if(textView.text.length == 0){
textView.text       = @"This is some placeholder text.";
textView.textColor  = [UIColor lightGrayColor];
textView.selectedRange = NSMakeRange(0, 0);
}
}


-(void)textViewDidChangeSelection:(UITextView *)textView{
if(textView.textColor == [UIColor lightGrayColor] && (textView.selectedRange.location != 0 || textView.selectedRange.length != 0)){
textView.selectedRange = NSMakeRange(0, 0);
}
}
- (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是保存文本视图的属性。这将完成任务。

您可以在文本视图上设置标签。

MyUITextView. h相关链接

@interface MyUITextView : UITextView {
UILabel* _placeholderLabel;
}


@property(nonatomic, assign)NSString *placeholder;

我的UITextView. m

@implementation MyUITextView


- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
// Create placeholder
viewFrame = CGRectMake(0, 0, frame.size.width, 15);
_placeholderLabel = [[UILabel alloc] initWithFrame:viewFrame];
_placeholderLabel.textColor = [UIColor lightGrayColor];
[self addSubview:_placeholderLabel];


// Add text changed notification
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChanged:) name:UITextViewTextDidChangeNotification object:nil];
}
return self;
}


- (void)setPlaceholder:(NSString *)placeholder {
_placeholderLabel.text = placeholder;
}


- (NSString*)placeholder {
return _placeholderLabel.text;
}


#pragma mark UITextViewTextDidChangeNotification


- (void)textChanged:(NSNotification *)notification {
_placeholderLabel.hidden = ([self.text lenght] == 0);
}


@end

在尝试了一些建议的方法和发布到github之后,我编写了一个更清晰的实现。

与此处介绍的其他方法相比,一些关键改进:

  • 不要在drawRect:中分配UILabel。(请永远不要这样做。)
  • 不将文本视图的当前文本与所需的占位符进行比较以交换颜色。
  • 在听写活动时隐藏占位符(如UITextField)。

我能够使用ALOT更少的代码将“占位符”添加到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;

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

我修改了Sam Soffes的实现以使用iOS7:

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


if (_shouldDrawPlaceholder)
{
UIEdgeInsets insets = self.textContainerInset;
CGRect placeholderRect = CGRectMake(
insets.left + self.textContainer.lineFragmentPadding,
insets.top,
self.frame.size.width - insets.left - insets.right,
self.frame.size.height - insets.top - insets.bottom);


[_placeholderText drawWithRect:placeholderRect
options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine
attributes:self.placeholderAttributes
context:nil];
}
}


- (NSDictionary *)placeholderAttributes
{
if (_placeholderAttributes == nil)
{
_placeholderAttributes = @
{
NSFontAttributeName : self.font,
NSForegroundColorAttributeName : self.placeholderColor
};
}


return _placeholderAttributes;
}

请记住在可能会更改字体和其他可能影响它们的主题的方法中设置_placeholderAttribues = nil。如果这不bug你,你可能还想跳过属性字典的“懒惰”制作。

编辑:

如果您希望占位符在自动布局动画等之后看起来很好,请记住在setBound的覆盖版本中调用setNeedsDisplay。

杰森的回答在iOS7中看起来有点偏离,通过调整_placeHolderLabel的偏移量来修复它:

- (void)drawRect:(CGRect)rect
{
if( [[self placeholder] length] > 0 )
{
if (_placeHolderLabel == nil )
{
if ([[UIDevice currentDevice].systemVersion floatValue] >= 7)
_placeHolderLabel = [[UILabel alloc] initWithFrame:CGRectMake(4,8,self.bounds.size.width - 8,0)];
else
_placeHolderLabel = [[UILabel alloc] initWithFrame:CGRectMake(8,8,self.bounds.size.width - 16,0)];
_placeHolderLabel.lineBreakMode = NSLineBreakByWordWrapping;
_placeHolderLabel.numberOfLines = 0;
_placeHolderLabel.font = self.font;
_placeHolderLabel.backgroundColor = [UIColor clearColor];
_placeHolderLabel.textColor = self.placeholderColor;
_placeHolderLabel.alpha = 0;
_placeHolderLabel.tag = 999;
[self addSubview:_placeHolderLabel];
}


_placeHolderLabel.text = self.placeholder;
[_placeHolderLabel sizeToFit];
[self sendSubviewToBack:_placeHolderLabel];
}


if( [[self text] length] == 0 && [[self placeholder] length] > 0 )
{
[[self viewWithTag:999] setAlpha:1];
}


[super drawRect:rect];
}

看看UT占位符文本视图

这是UITextView的一个方便的子类,它支持与UITextField类似的占位符。主要特点:

  • 不使用子视图
  • 不覆盖DrawRect:
  • 占位符可以是任意长度,并以与通常文本相同的方式呈现

我扩展了KmKndy的回答,以便占位符保持可见,直到用户开始编辑UITextView而不仅仅是点击它。这反映了Twitter和Facebook应用程序中的功能。如果用户直接输入或粘贴文本,我的解决方案不需要你子类化和工作!

占位符示例Twitter App

- (void)textViewDidChangeSelection:(UITextView *)textView{
if ([textView.text isEqualToString:@"What's happening?"] && [textView.textColor isEqual:[UIColor lightGrayColor]])[textView setSelectedRange:NSMakeRange(0, 0)];


}


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


[textView setSelectedRange:NSMakeRange(0, 0)];
}


- (void)textViewDidChange:(UITextView *)textView
{
if (textView.text.length != 0 && [[textView.text substringFromIndex:1] isEqualToString:@"What's happening?"] && [textView.textColor isEqual:[UIColor lightGrayColor]]){
textView.text = [textView.text substringToIndex:1];
textView.textColor = [UIColor blackColor]; //optional


}
else if(textView.text.length == 0){
textView.text = @"What's happening?";
textView.textColor = [UIColor lightGrayColor];
[textView setSelectedRange:NSMakeRange(0, 0)];
}
}


- (void)textViewDidEndEditing:(UITextView *)textView
{
if ([textView.text isEqualToString:@""]) {
textView.text = @"What's happening?";
textView.textColor = [UIColor lightGrayColor]; //optional
}
[textView resignFirstResponder];
}


- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{
if (textView.text.length > 1 && [textView.text isEqualToString:@"What's happening?"]) {
textView.text = @"";
textView.textColor = [UIColor blackColor];
}


return YES;
}

请记住在创建时使用确切的文本设置myUITextView。

UITextView *myUITextView = [[UITextView alloc] init];
myUITextView.delegate = self;
myUITextView.text = @"What's happening?";
myUITextView.textColor = [UIColor lightGrayColor]; //optional

并在包含这些方法之前使父类成为UITextView委托。

@interface MyClass () <UITextViewDelegate>
@end

如果您正在寻找一种简单的方法来实现这一点,请尝试我的方法:

- (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包含您的占位符

我找到了自己的解决方案

- (void)textViewDidBeginEditing:(UITextView *)textView
{
if ([textView.text isEqualToString:PLACEHOLDER_TEXT])
{
textView.textColor = [UIColor lightGrayColor];
dispatch_async(dispatch_get_main_queue(), ^
{
textView.selectedRange = NSMakeRange(0, 0);
});
}
else
{
textView.textColor = [UIColor blackColor];
}


[textView becomeFirstResponder];
}


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


[textView resignFirstResponder];
}


- (BOOL)textView:(UITextView *)textView
shouldChangeTextInRange:(NSRange)range
replacementText:(NSString *)text
{
if (range.location == 0 && range.length == [[textView text] length] && [text isEqualToString:@""])
{
textView.text = PLACEHOLDER_TEXT;
textView.textColor = [UIColor lightGrayColor];


dispatch_async(dispatch_get_main_queue(), ^
{
textView.selectedRange = NSMakeRange(0, 0);
});


return NO;
}


if ([textView.text isEqualToString:PLACEHOLDER_TEXT])
{
textView.text = @"";
textView.textColor = [UIColor blackColor];
}


return YES;
}

如果有人需要Swift的解决方案:

将UITextView添加到您的类

var placeHolderText = "Placeholder Text..."


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


func textViewShouldBeginEditing(textView: UITextView) -> Bool {


self.textView.textColor = .black


if(self.textView.text == placeHolderText) {
self.textView.text = ""
}


return true
}


func textViewDidEndEditing(textView: UITextView) {
if(textView.text == "") {
self.textView.text = placeHolderText
self.textView.textColor = .lightGray
}
}


override func viewWillAppear(animated: Bool) {


if(currentQuestion.answerDisplayValue == "") {
self.textView.text = placeHolderText
self.textView.textColor = .lightGray
} else {
self.textView.text = "xxx" // load default text / or stored
self.textView.textColor = .black
}
}

下面是“SAMTextView”ObjC代码的Swift端口,作为对该问题的首批回复之一发布。我在iOS8上进行了测试。我调整了几件事,包括占位符文本放置的边界偏移量,因为原始位置太高太远(在该帖子的一条评论中使用了建议)。

我知道有很多简单的解决方案,但我喜欢将UITextView子类化的方法,因为它是可重用的,并且我不必将使用它的类与机制弄乱。

Swift 2.2:

import UIKit


class PlaceholderTextView: UITextView {


@IBInspectable var placeholderColor: UIColor = UIColor.lightGrayColor()
@IBInspectable var placeholderText: String = ""


override var font: UIFont? {
didSet {
setNeedsDisplay()
}
}


override var contentInset: UIEdgeInsets {
didSet {
setNeedsDisplay()
}
}


override var textAlignment: NSTextAlignment {
didSet {
setNeedsDisplay()
}
}


override var text: String? {
didSet {
setNeedsDisplay()
}
}


override var attributedText: NSAttributedString? {
didSet {
setNeedsDisplay()
}
}


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


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


private func setUp() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(PlaceholderTextView.textChanged(_:)),
name: UITextViewTextDidChangeNotification, object: self)
}


func textChanged(notification: NSNotification) {
setNeedsDisplay()
}


func placeholderRectForBounds(bounds: CGRect) -> CGRect {
var x = contentInset.left + 4.0
var y = contentInset.top  + 9.0
let w = frame.size.width - contentInset.left - contentInset.right - 16.0
let h = frame.size.height - contentInset.top - contentInset.bottom - 16.0


if let style = self.typingAttributes[NSParagraphStyleAttributeName] as? NSParagraphStyle {
x += style.headIndent
y += style.firstLineHeadIndent
}
return CGRect(x: x, y: y, width: w, height: h)
}


override func drawRect(rect: CGRect) {
if text!.isEmpty && !placeholderText.isEmpty {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = textAlignment
let attributes: [ String: AnyObject ] = [
NSFontAttributeName : font!,
NSForegroundColorAttributeName : placeholderColor,
NSParagraphStyleAttributeName  : paragraphStyle]


placeholderText.drawInRect(placeholderRectForBounds(bounds), withAttributes: attributes)
}
super.drawRect(rect)
}
}

Swift 4.2:

import UIKit


class PlaceholderTextView: UITextView {


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


override var font: UIFont? {
didSet {
setNeedsDisplay()
}
}


override var contentInset: UIEdgeInsets {
didSet {
setNeedsDisplay()
}
}


override var textAlignment: NSTextAlignment {
didSet {
setNeedsDisplay()
}
}


override var text: String? {
didSet {
setNeedsDisplay()
}
}


override var attributedText: NSAttributedString? {
didSet {
setNeedsDisplay()
}
}


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


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


private func setUp() {
NotificationCenter.default.addObserver(self,
selector: #selector(self.textChanged(notification:)),
name: Notification.Name("UITextViewTextDidChangeNotification"),
object: nil)
}


@objc func textChanged(notification: NSNotification) {
setNeedsDisplay()
}


func placeholderRectForBounds(bounds: CGRect) -> CGRect {
var x = contentInset.left + 4.0
var y = contentInset.top  + 9.0
let w = frame.size.width - contentInset.left - contentInset.right - 16.0
let h = frame.size.height - contentInset.top - contentInset.bottom - 16.0


if let style = self.typingAttributes[NSAttributedString.Key.paragraphStyle] as? NSParagraphStyle {
x += style.headIndent
y += style.firstLineHeadIndent
}
return CGRect(x: x, y: y, width: w, height: h)
}


override func draw(_ rect: CGRect) {
if text!.isEmpty && !placeholderText.isEmpty {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = textAlignment
let attributes: [NSAttributedString.Key: Any] = [
NSAttributedString.Key(rawValue: NSAttributedString.Key.font.rawValue) : font!,
NSAttributedString.Key(rawValue: NSAttributedString.Key.foregroundColor.rawValue) : placeholderColor,
NSAttributedString.Key(rawValue: NSAttributedString.Key.paragraphStyle.rawValue)  : paragraphStyle]


placeholderText.draw(in: placeholderRectForBounds(bounds: bounds), withAttributes: attributes)
}
super.draw(rect)
}
}

简单的Swift3解决方案

UITextViewDelegate添加到您的类

设置yourTextView.delegate = self

创建placeholderLabel并将其放置在yourTextView

现在只需在textViewDidChange上动画placeholderLabel.alpha

  func textViewDidChange(_ textView: UITextView) {
let newAlpha: CGFloat = textView.text.isEmpty ? 1 : 0
if placeholderLabel.alpha != newAlpha {
UIView.animate(withDuration: 0.3) {
self.placeholderLabel.alpha = newAlpha
}
}
}

您可能必须使用placeholderLabel位置才能正确设置它,但这不应该太难

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

延伸现有的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";

…占位符将在文本中显示在…之上。当您设置text值时,不会调用任何常规通知,因此我无法弄清楚如何调用我的函数来决定是否显示/隐藏占位符。

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

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

或者,您可以设置text值,然后调用checkIfNeedToDisplayPlaceholder

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

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

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

另一个答案:

将IB中的UITextView类更改为GCPlaceholderTextView 并设置placeholder属性

这里有一个简单而聪明的方法来获得完美的行为。

让我们从UITextField借用占位符。

输入图片描述

  1. 设置一个文本字段并将其文本设置为透明。

    self.placeholderTextField = [[UITextField alloc] init];
    
    
    /* adjust the frame to fit it in the first line of your textView */
    self.placeholderTextField.frame = CGRectMake(0.0, 0.0, yourTextView.width, 30.0);
    
    
    self.placeholderTextField.textColor = [UIColor clearColor];
    self.placeholderTextField.userInteractionEnabled = NO;
    self.placeholderTextField.font = yourTextView.font;
    self.placeholderTextField.placeholder = @"sample placeholder";
    [yourTextView addSubview:self.placeholderTextField];
    
  2. Set textView's delegate and synchronize the textField and textView.

    yourTextView.delegate = self;
    

    然后

    - (void)textViewDidChange:(UITextView *)textView {
    
    
    self.placeholderTextField.text = textView.text;
    
    
    }
    
  3. That's all.

在. h类

@interface RateCommentViewController : UIViewController<UITextViewDelegate>{IBoutlet UITextview *commentTxtView;}

在. m类

- (void)viewDidLoad{
commentTxtView.text = @"Comment";
commentTxtView.textColor = [UIColor lightGrayColor];
commentTxtView.delegate = self;
}


- (BOOL) textViewShouldBeginEditing:(UITextView *)textView
{
commentTxtView.text = @"";
commentTxtView.textColor = [UIColor blackColor];
return YES;
}


-(void) textViewDidChange:(UITextView *)textView
{
if(commentTxtView.text.length == 0){
commentTxtView.textColor = [UIColor lightGrayColor];
commentTxtView.text = @"Comment";
[commentTxtView resignFirstResponder];
}
}

我建议使用SZTextView

https://github.com/glaszig/SZTextView

storyboard添加默认的UITextView,然后将其自定义类更改为SZTextView,如下所示

输入图片描述

然后您将在Attribute Inspector中看到两个新选项

输入图片描述

- (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中创建占位符,但您可以通过此生成像占位符这样的效果。

  - (void)viewDidLoad{
commentTxtView.text = @"Comment";
commentTxtView.textColor = [UIColor lightGrayColor];
commentTxtView.delegate = self;


}
- (BOOL) textViewShouldBeginEditing:(UITextView *)textView
{
commentTxtView.text = @"";
commentTxtView.textColor = [UIColor blackColor];
return YES;
}


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


if(commentTxtView.text.length == 0){
commentTxtView.textColor = [UIColor lightGrayColor];
commentTxtView.text = @"Comment";
[commentTxtView resignFirstResponder];
}
}

或者您可以在文本视图中添加标签,就像

       lbl = [[UILabel alloc] initWithFrame:CGRectMake(10.0, 0.0,textView.frame.size.width - 10.0, 34.0)];




[lbl setText:kDescriptionPlaceholder];
[lbl setBackgroundColor:[UIColor clearColor]];
[lbl setTextColor:[UIColor lightGrayColor]];
textView.delegate = self;


[textView addSubview:lbl];

并设置

- (void)textViewDidEndEditing:(UITextView *)theTextView
{
if (![textView hasText]) {
lbl.hidden = NO;
}
}


- (void) textViewDidChange:(UITextView *)textView
{
if(![textView hasText]) {
lbl.hidden = NO;
}
else{
lbl.hidden = YES;
}
}

嗨,您可以使用IQKeyboard Manager中提供的IQTextView,它易于使用和集成,只需将文本视图的类设置为IQTextView,您可以使用其属性设置占位符标签与您想要的颜色。 您可以从IQKeyboardManager

下载库

或者您可以从cocoapods安装它。

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

这里我拿

UILabel * lbl;

然后在. m下的viewdicLoad中声明它

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占位符已准备就绪!

一种更简单的方法是创建一个辅助UITextView,它具有与原始文本视图相同的所有属性,除了不同的text Color,并具有约束以确保它们保持对齐。然后,当任何字符输入到主文本视图时,隐藏克隆的文本视图,否则显示带有一些文本的克隆文本视图。

这可以通过多种方式实现,但一个相对干净的方法是子类化UITextView并将所有这些逻辑保留在子类中。

因此,子类UITextView并允许它懒洋洋地创建它的占位符视图:

接口文件:

@interface FOOTextView : UITextView <UITextViewDelegate>


@property (nonatomic, copy) NSString *placeholderText;


- (void)checkPlaceholder;


@end

实现文件:

#import "FOOTextView.h"


@interface FOOTextView ()


@property (nonatomic, strong) UITextView *placeholderTextView;


@end


@implementation FOOTextView


- (void)checkPlaceholder {
// Hide the placeholder text view if we've got any text
self.placeholderTextView.hidden = (self.text.length > 0 || self.attributedText.length > 0);
}


- (void)setPlaceholderText:(NSString *)placeholderText {
_placeholderText = [placeholderText copy];


// Setup the placeholder text view if we haven't already
[self setupPlaceholderTextView];


// Apply the placeholder text to the placeholder text view
self.placeholderTextView.text = placeholderText;
}


- (void)setupPlaceholderTextView {
if (!self.placeholderTextView) {


// Setup the place holder text view, duplicating our visual setup
self.placeholderTextView = [[UITextView alloc] initWithFrame:CGRectZero];
self.placeholderTextView.translatesAutoresizingMaskIntoConstraints = NO;
self.placeholderTextView.textColor = self.placeholderTextColor ? self.placeholderTextColor : [UIColor colorWithRed:199.f/255.f green:199.f/255.f blue:205.f/255.f alpha:1.f];
self.placeholderTextView.userInteractionEnabled = NO;
self.placeholderTextView.font = self.font;
self.placeholderTextView.textAlignment = self.textAlignment;
self.placeholderTextView.backgroundColor = self.backgroundColor;
self.placeholderTextView.editable = NO;


// Our background color must be clear for the placeholder text view to show through
self.backgroundColor = [UIColor clearColor];


// Insert the placeholder text view into our superview, below ourself so it shows through
[self.superview insertSubview:self.placeholderTextView belowSubview:self];


// Setup constraints to ensure the placeholder text view stays aligned with us
NSLayoutConstraint *constraintCenterX = [NSLayoutConstraint constraintWithItem:self.placeholderTextView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1.f constant:0.f];
NSLayoutConstraint *constraintCenterY = [NSLayoutConstraint constraintWithItem:self.placeholderTextView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.f constant:0.f];
NSLayoutConstraint *constraintWidth = [NSLayoutConstraint constraintWithItem:self.placeholderTextView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1.f constant:0.f];
NSLayoutConstraint *constraintHeight = [NSLayoutConstraint constraintWithItem:self.placeholderTextView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeHeight multiplier:1.f constant:0.f];
NSArray *constraints = @[constraintCenterX, constraintCenterY, constraintWidth, constraintHeight];
[self.superview addConstraints:constraints];


}
}


- (void)setPlaceholderTextColor:(UIColor *)placeholderTextColor {
_placeholderTextColor = placeholderTextColor;
self.placeholderTextView.textColor = _placeholderTextColor;
}


- (void)setBackgroundColor:(UIColor *)backgroundColor {
// We don't want a background color ourselves, instead we want our placeholder text view to have the desired background color
[self.placeholderTextView setBackgroundColor:backgroundColor];
}


- (void)removeFromSuperview {
// Ensure we also remove our placeholder text view
[self.placeholderTextView removeFromSuperview];
self.placeholderTextView = nil;
[super removeFromSuperview];
}


#pragma mark - Text View Delegation
- (void)textViewDidChange:(UITextView *)textView {
[self checkPlaceholder];
}


@end

使用上述类,如果您将FOOTextView的委托实例设置为自身,则一切都将开箱即用:

FOOTextView *myTextView = ...
myTextView.placeholderText = @"What's on your mind?";
myTextView.placeholderTextColor = [UIColor lightGrayColor];
myTextView.delegate = myTextView;

如果您希望另一个对象作为委托接管,那么您只需要在text ViewdicChange:委托方法中调用文本视图的check Place的方法,例如;

FOOTextView *myTextView = ...
myTextView.placeholderText = @"What's on your mind?";
myTextView.placeholderTextColor = [UIColor lightGrayColor];
myTextView.delegate = self;
self.myTextView = myTextView;


- (void)textViewDidChange:(UITextView *)textView {
// Call the checkPlaceholder method to update the visuals
[self.myTextView checkPlaceholder];
}

我知道这个问题已经有很多答案了,但我觉得其中任何一个都不够(至少在Swift中是这样)。我需要在我的UITextView中拥有UITextField的“占位符”功能(我想要确切的行为,包括文本显示属性、动画等,并且不想随着时间的推移而维护它)。我还想要一个提供与UITextField相同的精确边框的解决方案(不是现在看起来有点像的近似边框,而是一个看起来完全一样并且永远看起来完全一样的解决方案)。因此,虽然我最初并不喜欢在混音中加入额外的控件,但似乎为了实现我的目标,我必须使用实际的UITextField并让它完成工作。

此解决方案处理定位占位符并使字体在两个控件之间保持同步,以便占位符文本是输入到控件中的文本的确切字体和位置(许多其他解决方案没有解决这一问题)。

// This class is necessary to support "inset" (required to position placeholder
// appropriately in TextView)
//
class TextField: UITextField
{
var inset: UIEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0);


override func textRectForBounds(bounds: CGRect) -> CGRect
{
return UIEdgeInsetsInsetRect(bounds, inset);
}


override func placeholderRectForBounds(bounds: CGRect) -> CGRect
{
return UIEdgeInsetsInsetRect(bounds, inset);
}
}


// This class implements a UITextView that has a UITextField behind it, where the
// UITextField provides the border and the placeholder text functionality (so that the
// TextView looks and works like a UITextField).
//
class TextView : UITextView, UITextViewDelegate
{
var textField = TextField();


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


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


self.delegate = self;


// Create a background TextField with clear (invisible) text and disabled
self.textField.borderStyle = UITextBorderStyle.RoundedRect;
self.textField.textColor = UIColor.clearColor();
self.textField.userInteractionEnabled = false;


// Align the background TextView to where text appears in the TextField, so
// that any placeholder will be in the correct position.
self.textField.contentVerticalAlignment = UIControlContentVerticalAlignment.Top;
self.textField.inset = UIEdgeInsets(
top: self.textContainerInset.top,
left: self.textContainerInset.left + self.textContainer.lineFragmentPadding,
bottom: self.textContainerInset.bottom,
right: self.textContainerInset.right
);


// The background TextField should use the same font (for the placeholder)
self.textField.font = self.font;


self.addSubview(textField);
self.sendSubviewToBack(textField);
}


convenience init()
{
self.init(frame: CGRectZero, textContainer: nil)
}


override var font: UIFont?
{
didSet
{
// Keep the font of the TextView and background textField in sync
self.textField.font = self.font;
}
}


var placeholder: String? = nil
{
didSet
{
self.textField.placeholder = self.placeholder;
}
}


override func layoutSubviews()
{
super.layoutSubviews()
// Do not scroll the background textView
self.textField.frame = CGRectMake(0, self.contentOffset.y, self.frame.width, self.frame.height);
}


// UITextViewDelegate - Note: If you replace delegate, your delegate must call this
func scrollViewDidScroll(scrollView: UIScrollView)
{
// Do not scroll the background textView
self.textField.frame = CGRectMake(0, self.contentOffset.y, self.frame.width, self.frame.height);
}


// UITextViewDelegate - Note: If you replace delegate, your delegate must call this
func textViewDidChange(textView: UITextView)
{
// Updating the text in the background textView will cause the placeholder to
// appear/disappear (including any animations of that behavior - since the
// textView is doing this itself).
self.textField.text = self.text;
}
}

我刚刚发现,从iOS 10开始,您现在实际上可以将UITextView转换为UITextField方法,并在方法内部设置占位符。刚刚尝试过,它可以工作,而无需子类UITextView

这是一个对我有用的例子:

-(void)customizeTextField:(UITextField *)textField placeholder:(NSString *)pText withColor:(UIColor *)pTextColor{


textField.attributedPlaceholder = [[NSAttributedString alloc]
initWithString:pText
attributes:@{NSForegroundColorAttributeName:pTextColor}];
}

要将其用于UITextView,您只需使用像这样的转换将其传递给方法:

[self customizeTextField:(UITextField*)_myTextView placeholder:@"Placeholder" withColor:[UIColor blackColor]];

注意:经过测试,我发现该解决方案在iOS9.x上也可以正常工作,但在iOS8.x上导致崩溃

在UITextView占位符文本视图中支持图标占位符的简单类

@IBOutlet weak var tvMessage: PlaceholderTextView!
//  TODO: - Create Icon Text Attachment
let icon: NSTextAttachment = NSTextAttachment()
icon.image = UIImage(named: "paper-plane")
let iconString = NSMutableAttributedString(attributedString: NSAttributedString(attachment: icon))


tvMessage.icon = icon


//  TODO: - Attributes
let textColor = UIColor.gray
let lightFont = UIFont(name: "Helvetica-Light", size: tvMessage.font!.pointSize)
let italicFont = UIFont(name: "Helvetica-LightOblique", size: tvMessage.font!.pointSize)


//  TODO: - Placeholder Attributed String
let message = NSAttributedString(string: " " + "Personal Message", attributes: [ NSFontAttributeName: lightFont!,   NSForegroundColorAttributeName: textColor])
iconString.append(message)
// TODO: - Italic Placeholder Part
let option = NSAttributedString(string: " " + "Optional", attributes: [ NSFontAttributeName: italicFont!, NSForegroundColorAttributeName: textColor])
iconString.append(option)


tvMessage.attributedPlaceHolder = iconString


tvMessage.layoutSubviews()

空 with text

在浏览(并尝试)了大多数针对UITextView这个看似明显但缺失的特性提出的解决方案后,我发现最接近的是来自BobDickinson的解决方案。但我不喜欢不得不求助于一个全新的子类[我更喜欢下拉式类别来进行如此简单的功能添加],也不是它拦截了UITextView代理方法,这可能会弄乱你现有的UITextView处理代码。所以这是我对一个适用于任何现有UITextView实例的下拉式类别的看法…

#import <objc/runtime.h>


// Private subclass needed to override placeholderRectForBounds: to correctly position placeholder
@interface _TextField : UITextField
@property UIEdgeInsets insets;
@end
@implementation _TextField
- (CGRect)placeholderRectForBounds:(CGRect)bounds
{
CGRect rect = [super placeholderRectForBounds:bounds];
return UIEdgeInsetsInsetRect(rect, _insets);
}
@end


@implementation UITextView (Placeholder)


static const void *KEY;


- (void)setPlaceholder:(NSString *)placeholder
{
_TextField *textField = objc_getAssociatedObject(self, &KEY);
if (!textField) {
textField = [_TextField.alloc initWithFrame:self.bounds];
textField.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
textField.userInteractionEnabled = NO;
textField.font = self.font;


textField.contentVerticalAlignment = UIControlContentVerticalAlignmentTop;
textField.insets = UIEdgeInsetsMake(self.textContainerInset.top,
self.textContainerInset.left + self.textContainer.lineFragmentPadding,
self.textContainerInset.bottom,
self.textContainerInset.right);
[self addSubview:textField];
[self sendSubviewToBack:textField];


objc_setAssociatedObject(self, &KEY, textField, OBJC_ASSOCIATION_RETAIN);


[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(updatePlaceholder:) name:UITextViewTextDidChangeNotification object:nil];
}
textField.placeholder = placeholder;
}


- (NSString*)placeholder
{
UITextField *textField = objc_getAssociatedObject(self, &KEY);
return textField.placeholder;
}


- (void)updatePlaceholder:(NSNotification *)notification
{
UITextField *textField = objc_getAssociatedObject(self, &KEY);
textField.font = self.font;
[textField setAlpha:self.text.length? 0 : 1];
}


@end

它很容易使用,只是显而易见的

UITextView *myTextView = UITextView.new;
...
myTextView.placeholder = @"enter text here";

它的工作原理是在UITextView后面的正确位置添加一个用户信息字段,并利用这是占位符(因此您不必担心正确的颜色等),然后在您的UITextView更改为显示/隐藏此UITextField时监听通知(因此它不会干扰您现有的UITextView委托调用)。并且没有涉及魔法数字…:-)

objc_setAssociatedObject()/objc_getAssociatedObject()是为了避免必须子类化UITextView。[不幸的是,要正确定位UITextField,有必要引入一个'私有'子类,以覆盖占位符RectForBound:]

改编自BobDickinson的Swift答案。

我通读了所有这些,但想出了一个非常简短的Swift 3解决方案,该解决方案在我所有的测试中都有效。它可以经得起更多的通用性,但过程很简单。这就是我称之为“TextView吃素”的整个事情。

import UIKit


class TextViewWithPlaceholder: UITextView {


public var placeholder: String?
public var placeholderColor = UIColor.lightGray


private var placeholderLabel: UILabel?


// Set up notification listener when created from a XIB or storyboard.
// You can also set up init() functions if you plan on creating
// these programmatically.
override func awakeFromNib() {
super.awakeFromNib()


NotificationCenter.default.addObserver(self,
selector: #selector(TextViewWithPlaceholder.textDidChangeHandler(notification:)),
name: .UITextViewTextDidChange,
object: self)


placeholderLabel = UILabel()
placeholderLabel?.alpha = 0.85
placeholderLabel?.textColor = placeholderColor
}


// By using layoutSubviews, you can size and position the placeholder
// more accurately. I chose to hard-code the size of the placeholder
// but you can combine this with other techniques shown in previous replies.
override func layoutSubviews() {
super.layoutSubviews()


placeholderLabel?.textColor = placeholderColor
placeholderLabel?.text = placeholder


placeholderLabel?.frame = CGRect(x: 6, y: 4, width: self.bounds.size.width-16, height: 24)


if text.isEmpty {
addSubview(placeholderLabel!)
bringSubview(toFront: placeholderLabel!)
} else {
placeholderLabel?.removeFromSuperview()
}
}


// Whenever the text changes, just trigger a new layout pass.
func textDidChangeHandler(notification: Notification) {
layoutSubviews()
}
}

这完美地模仿了UITextField的占位符,其中占位符文本一直保留到您实际键入某些内容为止。

private let placeholder = "Type here"


@IBOutlet weak var textView: UITextView! {
didSet {
textView.textColor = UIColor.lightGray
textView.text = placeholder
textView.selectedRange = NSRange(location: 0, length: 0)
}
}


extension ViewController: UITextViewDelegate {


func textViewDidChangeSelection(_ textView: UITextView) {
// Move cursor to beginning on first tap
if textView.text == placeholder {
textView.selectedRange = NSRange(location: 0, length: 0)
}
}


func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if textView.text == placeholder && !text.isEmpty {
textView.text = nil
textView.textColor = UIColor.black
textView.selectedRange = NSRange(location: 0, length: 0)
}
return true
}


func textViewDidChange(_ textView: UITextView) {
if textView.text.isEmpty {
textView.textColor = UIColor.lightGray
textView.text = placeholder
}
}
}

只需创建UITextView@IBDesignable子类:

@IBDesignable class AttributedTextView: UITextView {


private let placeholderLabel = UILabel()


@IBInspectable var placeholder: String = "" {


didSet {


setupPlaceholderLabelIfNeeded()
textViewDidChange()
}
}


override var text: String! {


didSet {
textViewDidChange()
}
}


//MARK: - Initialization


override func awakeFromNib() {
super.awakeFromNib()


setupPlaceholderLabelIfNeeded()
NotificationCenter.default.addObserver(self, selector: #selector(textViewDidChange), name: .UITextViewTextDidChange, object: nil)
}


//MARK: - Deinitialization


deinit {
NotificationCenter.default.removeObserver(self)
}


//MARK: - Internal


func textViewDidChange() {


placeholderLabel.isHidden = !text.isEmpty
layoutIfNeeded()
}


//MARK: - Private


private func setupPlaceholderLabelIfNeeded() {


placeholderLabel.removeFromSuperview()
placeholderLabel.frame = CGRect(x: 0, y: 8, width: frame.size.width, height: 0)
placeholderLabel.textColor = UIColor.lightGray
placeholderLabel.text = placeholder


placeholderLabel.sizeToFit()


insertSubview(placeholderLabel, at: 0)
}
}

然后简单地在身份检查员中设置占位符:

在此处输入图片描述

修改占位符文本颜色的最简单方法是通过XCode故事板界面生成器。选择感兴趣的UITextField并打开右侧的身份检查器。单击用户定义的运行时属性中的加号并添加一个新行,其中键路径为_颜色,键入为颜色,值为所需颜色。

我已经用swft写了一个类。您可以在需要时导入这个类。

import UIKit

类自定义文本视图:UITextView{

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


private var placeholderLabelConstraints = [NSLayoutConstraint]()


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


@IBInspectable public var placeholderColor: UIColor = CustomTextView.Constants.defaultiOSPlaceholderColor {
didSet {
placeholderLabel.textColor = placeholderColor
}
}


override public var font: UIFont! {
didSet {
placeholderLabel.font = font
}
}


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


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


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


override public 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() {
NSNotificationCenter.defaultCenter().addObserver(self,
selector: #selector(textDidChange),
name: UITextViewTextDidChangeNotification,
object: nil)


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


private func updateConstraintsForPlaceholderLabel() {
var newConstraints = NSLayoutConstraint.constraintsWithVisualFormat("H:|-(\(textContainerInset.left + textContainer.lineFragmentPadding))-[placeholder]",
options: [],
metrics: nil,
views: ["placeholder": placeholderLabel])
newConstraints += NSLayoutConstraint.constraintsWithVisualFormat("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.hidden = !text.isEmpty
}


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


deinit {
NSNotificationCenter.defaultCenter().removeObserver(self,
name: UITextViewTextDidChangeNotification,
object: nil)
}

}

在此处输入图片描述


模拟本地占位符


一个常见的抱怨是iOS没有为文本视图提供本机占位符功能。下面的UITextView扩展试图通过提供本机功能的便利来解决这个问题,只需一条线代码即可将占位符添加到文本视图实例。

这种解决方案的缺点是,因为它菊花链委托调用,它容易受到(不太可能)在iOS更新中对UITextView代理协议的更改的攻击。具体来说,如果iOS添加了新的协议方法,并且您在带有占位符的文本视图的委托中实现了它们中的任何一个,除非您更新了扩展以转发这些调用,否则不会调用这些方法。

或者,内联占位符 的答案是坚如磐石的,尽可能简单。


使用示例:


   •如果获得占位符不要的文本视图使用UITextViewDelegate

    /* Swift 3 */


class NoteViewController : UIViewController {
@IBOutlet weak var noteView: UITextView!
override func viewDidLoad() {
noteView.addPlaceholder("Enter some text...",  color: UIColor.lightGray)
}
}

                                            --OR--

   •如果获得占位符确实的文本视图使用UITextViewDelegate

    /* Swift 3 */


class NoteViewController : UIViewController, UITextViewDelegate {
@IBOutlet weak var noteView: UITextView!
override func viewDidLoad() {
noteView.addPlaceholder("Phone #", color: UIColor.lightGray, delegate: self)
}
}

实现(UITextView扩展):


/* Swift 3 */


extension UITextView: UITextViewDelegate
{


func addPlaceholder(_ placeholderText : String,
color : UIColor? = UIColor.lightGray,
delegate : UITextViewDelegate? = nil) {


self.delegate = self             // Make receiving textview instance a delegate
let placeholder = UITextView()   // Need delegate storage ULabel doesn't provide
placeholder.isUserInteractionEnabled = false  //... so we *simulate* UILabel
self.addSubview(placeholder)     // Add to text view instance's view tree
placeholder.sizeToFit()          // Constrain to fit inside parent text view
placeholder.tintColor = UIColor.clear // Unused in textviews. Can host our 'tag'
placeholder.frame.origin = CGPoint(x: 5, y: 0) // Don't cover I-beam cursor
placeholder.delegate = delegate  // Use as cache for caller's delegate
placeholder.font = UIFont.italicSystemFont(ofSize: (self.font?.pointSize)!)
placeholder.text = placeholderText
placeholder.textColor = color
}


      

func findPlaceholder() -> UITextView? { // find placeholder by its tag
for subview in self.subviews {
if let textview = subview as? UITextView {
if textview.tintColor == UIColor.clear { // sneaky tagging scheme
return textview
}
}
}
return nil
}
     

/*
* Safely daisychain to caller delegate methods as appropriate...
*/


public func textViewDidChange(_ textView: UITextView) { // ←  need this delegate method
if let placeholder = findPlaceholder() {
placeholder.isHidden = !self.text.isEmpty // ← ... to do this
placeholder.delegate?.textViewDidChange?(textView)
}
}


/*
* Since we're becoming a delegate on behalf of this placeholder-enabled
* text view instance, we must forward *all* that protocol's activity expected
* by the instance, not just the particular optional protocol method we need to
* intercept, above.
*/


public func textViewDidEndEditing(_ textView: UITextView) {
if let placeholder = findPlaceholder() {
placeholder.delegate?.textViewDidEndEditing?(textView)
}
}


public func textViewDidBeginEditing(_ textView: UITextView) {
if let placeholder = findPlaceholder() {
placeholder.delegate?.textViewDidBeginEditing?(textView)
}
}


public  func textViewDidChangeSelection(_ textView: UITextView) {
if let placeholder = findPlaceholder() {
placeholder.delegate?.textViewDidChangeSelection?(textView)
}
}


public func textViewShouldEndEditing(_ textView: UITextView) -> Bool {
if let placeholder = findPlaceholder() {
guard let retval = placeholder.delegate?.textViewShouldEndEditing?(textView) else {
return true
}
return retval
}
return true
}


public func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
if let placeholder = findPlaceholder() {
guard let retval = placeholder.delegate?.textViewShouldBeginEditing?(textView) else {
return true
}
return retval
}
return true
}


public func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if let placeholder = findPlaceholder() {
guard let retval = placeholder.delegate?.textView?(textView, shouldChangeTextIn: range, replacementText: text) else {
return true
}
return retval
}
return true
}


public func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
if let placeholder = findPlaceholder() {
guard let retval = placeholder.delegate?.textView?(textView, shouldInteractWith: URL, in: characterRange, interaction:
interaction) else {
return true
}
return retval
}
return true
}


public func textView(_ textView: UITextView, shouldInteractWith textAttachment: NSTextAttachment, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
if let placeholder = findPlaceholder() {
guard let retval = placeholder.delegate?.textView?(textView, shouldInteractWith: textAttachment, in: characterRange, interaction: interaction) else {
return true
}
return retval
}
return true
}
}

1.作为像UITextView这样的基本iOS类的扩展,重要的是要知道此代码具有没有互动和任何未激活占位符的文本视图,例如尚未通过调用#E YZ 0初始化的文本视图实例

2.启用占位符的文本视图透明地变成#E YZ 0来跟踪字符计数,以控制占位符可见性。如果将委托传递给#E YZ 1,此代码将委托回调菊花链(即转发)到该委托。

作者正在研究如何检查#E YZ 0协议并自动代理它,而无需对每个方法进行硬编码。这将从方法签名更改和新方法添加到协议中接种代码。

Swift3.1

在尝试了所有快速的答案之后,这个答案可以节省我3个小时的研究时间。希望这有帮助。

  1. 确保您的文本字段(无论您拥有的自定义名称如何)指向Storyboard中的委托,并且具有带有yourCustomTextField的@IBOutlet

  2. 添加到viewDidLoad()以下内容,它将在加载视图时出现:

给我看看什么看起来像一个占位符:

yourCustomTextField = "Start typing..."
yourCustomTextField.textColor = .lightGray
  1. 在viewTitLoad之外但在同一个类内添加以下声明:UIViewController, UITextViewDelegate, UINavigationControllerDelegate

此代码将使您的CustomTextField在文本字段中键入时消失:

func textViewDidBeginEditing (_ textView: UITextView) {


if (textView.text == "Start typing...") {


textView.text = ""
textView.textColor = .black
}


textView.becomeFirstResponder()
}


func textViewDidEndEditing(_ textView: UITextView) {
if (textView.text == "") {


textView.text = "Start typing..."
textView.textColor = .lightGray
}


textView.resignFirstResponder()
}

这是Swift 3.1的代码

Jason George在第一个答案中的原始代码。

不要忘记在界面生成器中将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)
}
}

我创建了排名最高的答案的Swift 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
}
}
}

我建议使用pod'UITextView+占位符'

pod 'UITextView+Placeholder'

在您的代码

#import "UITextView+Placeholder.h"


////


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

另一种解决方案

import UIKit


protocol PlaceholderTextViewDelegate: class {


func placeholderTextViewDidChangeText(_ text: String)
func placeholderTextViewDidEndEditing(_ text: String)
}


final class PlaceholderTextView: UITextView {


weak var notifier: PlaceholderTextViewDelegate?
var ignoreEnterAction: Bool = true


var placeholder: String? {
didSet {
text = placeholder
selectedRange = NSRange(location: 0, length: 0)
}
}


var placeholderColor = UIColor.lightGray {
didSet {
if text == placeholder {
textColor = placeholderColor
}
}
}
var normalTextColor = UIColor.lightGray


var placeholderFont = UIFont.sfProRegular(28)


fileprivate var placeholderLabel: UILabel?


// MARK: - LifeCycle


override var text: String? {
didSet {
if text == placeholder {
textColor = placeholderColor
} else {
textColor = normalTextColor
}
}
}


init() {
super.init(frame: CGRect.zero, textContainer: nil)
awakeFromNib()
}


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


override func awakeFromNib() {
super.awakeFromNib()


self.delegate = self
}
}


extension PlaceholderTextView: UITextViewDelegate {


// MARK: - UITextViewDelegate
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {


if text == "" && textView.text == placeholder {
return false
}


if let placeholder = placeholder,
textView.text == placeholder,
range.location <= placeholder.count {
textView.text = ""
}


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


func textViewDidChange(_ textView: UITextView) {
if let placeholder = placeholder {
textView.text = textView.text.replacingOccurrences(of: placeholder, with: "")
}


if let placeholder = placeholder,
text?.isEmpty == true {
text = placeholder
textColor = placeholderColor


selectedRange = NSRange(location: 0, length: 0)
} else {
textColor = normalTextColor
}


notifier?.placeholderTextViewDidChangeText(textView.text)
}


func textViewDidChangeSelection(_ textView: UITextView) {
if let placeholder = placeholder,
text == placeholder {
selectedRange = NSRange(location: 0, length: 0)
}
}


func textViewDidEndEditing(_ textView: UITextView) {
notifier?.placeholderTextViewDidEndEditing(textView.text)


if let placeholder = placeholder,
text?.isEmpty == true {
text = placeholder
textColor = placeholderColor
selectedRange = NSRange(location: 0, length: 0)
} else {
textColor = normalTextColor
}
}
}

结果:

在此处输入图片描述

我遵循了此链接中的代码。只有7个简单的步骤。它向文本视图添加了一个UILabel,并在通过文本视图的textViewDidChangeSelection(_ textView: UITextView)委托方法从文本视图中输入或删除文本时隐藏/显示标签。我把这些步骤放在代码上方的注释中。

// 1. make sure to include the UITextViewDelegate
class YourClass: UITextViewDelegate {


@IBOutlet weak var textView : UITextView!


// 2. create placeholder textLabel
let placeHolderTextLabel: UILabel = {
let placeholderLabel = UILabel()
placeholderLabel.text = "Placeholder text..."
placeholderLabel.sizeToFit()
placeholderLabel.textColor = UIColor.lightGray
return placeholderLabel
}()


override func viewDidLoad() {
super.viewDidLoad()


// 3. set textView delegate
textView.delegate = self


configurePlaceholderTextLabel()
}




func configurePlaceholderTextLabel() {


// 4. add placeholder label to textView, set it's frame and font
textView.addSubview(placeHolderTextLabel)
placeHolderTextLabel.frame.origin = CGPoint(x: 5, y: (textView.font?.pointSize)! / 2)
placeHolderTextLabel.font = UIFont.systemFont(ofSize: (textView.font?.pointSize)!)


// 5. decide wether the placeHolderTextLabel is hidden or not depending on if there is or isn't text inside the textView
placeHolderTextLabel.isHidden = !textView.text.isEmpty


}


// 6. implement textView delegate method to update the placeHolderTextLabel when the text is changed
func textViewDidChangeSelection(_ textView: UITextView) {


// 7. decide wether the placeHolderTextLabel is hidden or not depending on if there is or isn't text inside the textView when text in textView is changed
placeHolderTextLabel.isHidden = !textView.text.isEmpty
}


}

这是我的UITextView版本,支持占位符。Swift 4.2 https://gist.github.com/hlung/c5dda3a0c2087e5ae6c1fce8822c4713

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

基于这里已经提出的一些很好的建议,我能够将UITextView的以下轻量级、与Interface-Builder兼容的子类放在一起:

  • 包括可配置的占位符文本,样式类似于UITextField
  • 不需要任何额外的子视图或约束。
  • 不需要ViewController的任何委托或其他行为。
  • 不需要任何通知。
  • 将该文本与查看字段text属性的任何外部类完全分开。

欢迎提出改进建议。

编辑1:如果以编程方式设置实际文本,则更新为重置占位符格式。

编辑2:现在可以以编程方式检索占位符文本颜色。

Swift 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 {
if showingPlaceholder {
removePlaceholderFormatting() // If the placeholder text is what's being changed, it's no longer the placeholder
}
super.text = newValue
}
}
@IBInspectable var placeholderText: String = ""
@IBInspectable var placeholderTextColor: UIColor = .placeholderText
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 public func becomeFirstResponder() -> Bool {
        

// If the current text is the placeholder, remove it
if showingPlaceholder {
text = nil
removePlaceholderFormatting()
}
return super.becomeFirstResponder()
}
    

override public func resignFirstResponder() -> Bool {
        

// If there's no text, put the placeholder back
if text.isEmpty {
showPlaceholderText()
}
return super.resignFirstResponder()
}
    

private func showPlaceholderText() {
        

text = placeholderText
showingPlaceholder = true
textColor = placeholderTextColor
}
    

private func removePlaceholderFormatting() {
        

showingPlaceholder = false
textColor = nil // Put the text back to the default, unmodified color
}
}

在斯威夫特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
}
}

TextView PlaceHolder在Swift中

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)
}


}

用法

在此处输入图片描述

一个更简单的答案,使用CATextLayer.

添加CATextLayerUITextView's层。 使用UITextViewDelegate方法,只需更改CATextLayer的颜色。

func txtViewPlaceholder() {
let textlayer = CATextLayer()


textlayer.frame = CGRect(x: 5, y: 5, width: 200, height: 18)
textlayer.contentsScale = UIScreen.main.scale
textlayer.fontSize = 12
textlayer.alignmentMode = kCAAlignmentLeft
textlayer.string = "Enter here"
textlayer.isWrapped = true
textlayer.name = "placeholder"
textlayer.backgroundColor = UIColor.white.cgColor
textlayer.foregroundColor = UIColor.black.cgColor


yourTxtVw.layer.insertSublayer(textlayer, at: 0)
}


func removeAddPlaceholder(remove: Bool, textView: UITextView) {
for layers in textView.layer.sublayers! where layers.name == "placeholder" {
        

if remove {
(layers as! CATextLayer).foregroundColor = UIColor.white.cgColor
} else {
(layers as! CATextLayer).foregroundColor = UIColor.black.cgColor
}
        

}
}




extension YourViewController : UITextViewDelegate {


func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
    

removeAddPlaceholder(remove: true, textView: textView)
    

return true
}


func textViewDidEndEditing(_ textView: UITextView) {
    

if textView.text.count <= 0 {
removeAddPlaceholder(remove: false, textView: textView)
}
}


}

在阅读了所有答案之后,我意识到我需要一些简单的、同时可重用的东西,这样我就可以向项目中的所有UITextViews添加相同的功能。我最终得到了以下代码:

extension UITextView {


// MARK: TextView PlaceHolderLabel Setup


func createPlaceHolderLabel(with text: String) {
let lbl = UILabel()
self.addSubview(lbl)


// Add your constraints here


lbl.text = text
lbl.textColor = .lightGray
}


// My Textview contains only one UILabel, and for my use case the below code works, tweak it according to your use case


// Lastly two methods to toggle between show and hide the placeholder label


func hidePlaceHolderLabel() {
guard let lbl = self.subviews.first(where: { $0 is UILabel }) else { return }
lbl.isHidden = true
}


func showPlaceHolderLabel() {
guard let lbl = self.subviews.first(where: { $0 is UILabel }) else { return }
lbl.isHidden = false
}

}

UILabel作为子视图添加到UITextView时,文本视图光标位置和UILabel位置将不匹配,因此在占位符文本之前留下一个空格

class ViewController: UIViewController, UITextViewDelegate {
var textView: UITextView!


override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(textView)
// Also setup textView constraints as per your need
// Add placeholder to your textView
// Leave one space before placeholder string
textView.createPlaceHolderLabel(with: " Address")
textView.delegate = self
}

然后在textViewdidChange方法中添加以下代码

func textViewDidChange(_ textView: UITextView) {
if textView.text.isEmpty {
textView.showPlaceHolderLabel()
} else {
textView.hidePlaceHolderLabel()
}
}

它可以在所有UITextViews中重复使用。