ios - UITextView中占位符

  显示原文与译文双语对照的内容

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

有人知道怎么做?

时间:

我对bcd的解决方案做了一些小小的修改,以便从xib文件,文本环绕和维护背景颜色进行初始化。 希望它能挽救别人的麻烦。

UIPlaceHolderTextView.h


#import <Foundation/Foundation.h>

@interface UIPlaceHolderTextView : UITextView

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

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

@end

UIPlaceHolderTextView.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 创建占位符文本使用以下 UITextViewDelegate 方法:


- (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

我对发布的任何解决方案都不太满意,因为它们有点重。 将视图添加到视图并不是真正理想的( 尤其在 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

它比其他的简单很多,因为它不使用 subviews ( 或者有漏洞) 。 随意使用它。

更新 11/10/11: 现在记录,支持界面构建器使用。

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

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

它与UITextField中的占位符功能不同,但它是封闭的。

我发现自己 place-holder verry容易模仿

  1. 在代码或者代码中将textview的textColor设置为 lightGrayColor ( 大多数时间)
  2. 确保textview的委托链接到文件的所有者,并在头文件中实现 UITextViewDelegate
  3. 将textview的默认文本设置为( 例如: "Foobar占位符")
  4. 实现:( BOOL ) textViewShouldBeginEditing: ( UITextView *)textView )

编辑:

如果要比较标记而不是文本,则更改标记。 如果用户删除了文本,也可能会意外删除部分占位符 @"Foobar placeholder". This,这意味着如果用户re-entered以下委托方法, -(BOOL) textViewShouldBeginEditing:(UITextView *) textView ,它不会像预期那样工作。 我试着色彩的文本比较的if语句,但发现在interfacebuilder中浅灰色的颜色设置不一样的浅灰色的颜色代码与 [UIColor lightGreyColor]


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

还可以在键盘返回和 [textView length] == 0时重置占位符文本

编辑:

为了使最后一部分更加清晰- 你可以在这里设置占位符文本:


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

你可以在 UITextView 上设置标签,方法是


[UITextView addSubView:lblPlaceHoldaer];

并将它的隐藏在 TextViewdidChange 方法上。

这是简单的&简单方式。

我就是这么做的:

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

UITextView2.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

这是一个容易的解决方案,表现完全一样的占位符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;
 }

}

( 安葬语句中的第二个检查是针对没有输入的情况,用户按退格键)

将你的类设置为 UITextViewDelegate 。 在viewDidLoad中,你应该像


- (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;
}

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

Example of PlaceholderTwitter 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 (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

对不起,添加另一个答案,但是我只是把这样的东西,这个创造了closest-to-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: 1];
 }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);
 }
}

...