我的应用程序使用UITextView。现在我想让UITextView有一个占位符,类似于你可以为UITextField设置的占位符。
如何做到这一点?
我的应用程序使用UITextView。现在我想让UITextView有一个占位符,类似于你可以为UITextField设置的占位符。
如何做到这一点?
当前回答
我对发布的任何解决方案都不太满意,因为它们有点重。向视图中添加视图并不理想(尤其是在drawRect:)。它们都有漏洞,这也是不可接受的。
这是我的解决方案:SAMTextView
SAMTextView.h
//
// SAMTextView.h
// SAMTextView
//
// Created by Sam Soffes on 8/18/10.
// Copyright 2010-2013 Sam Soffes. All rights reserved.
//
#import <UIKit/UIKit.h>
/**
UITextView subclass that adds placeholder support like UITextField has.
*/
@interface SAMTextView : UITextView
/**
The string that is displayed when there is no other text in the text view.
The default value is `nil`.
*/
@property (nonatomic, strong) NSString *placeholder;
/**
The color of the placeholder.
The default is `[UIColor lightGrayColor]`.
*/
@property (nonatomic, strong) UIColor *placeholderTextColor;
/**
Returns the drawing rectangle for the text views’s placeholder text.
@param bounds The bounding rectangle of the receiver.
@return The computed drawing rectangle for the placeholder text.
*/
- (CGRect)placeholderRectForBounds:(CGRect)bounds;
@end
SAMTextView.m
//
// SAMTextView.m
// SAMTextView
//
// Created by Sam Soffes on 8/18/10.
// Copyright 2010-2013 Sam Soffes. All rights reserved.
//
#import "SAMTextView.h"
@implementation SAMTextView
#pragma mark - Accessors
@synthesize placeholder = _placeholder;
@synthesize placeholderTextColor = _placeholderTextColor;
- (void)setText:(NSString *)string {
[super setText:string];
[self setNeedsDisplay];
}
- (void)insertText:(NSString *)string {
[super insertText:string];
[self setNeedsDisplay];
}
- (void)setAttributedText:(NSAttributedString *)attributedText {
[super setAttributedText:attributedText];
[self setNeedsDisplay];
}
- (void)setPlaceholder:(NSString *)string {
if ([string isEqual:_placeholder]) {
return;
}
_placeholder = string;
[self setNeedsDisplay];
}
- (void)setContentInset:(UIEdgeInsets)contentInset {
[super setContentInset:contentInset];
[self setNeedsDisplay];
}
- (void)setFont:(UIFont *)font {
[super setFont:font];
[self setNeedsDisplay];
}
- (void)setTextAlignment:(NSTextAlignment)textAlignment {
[super setTextAlignment:textAlignment];
[self setNeedsDisplay];
}
#pragma mark - NSObject
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self name:UITextViewTextDidChangeNotification object:self];
}
#pragma mark - UIView
- (id)initWithCoder:(NSCoder *)aDecoder {
if ((self = [super initWithCoder:aDecoder])) {
[self initialize];
}
return self;
}
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
[self initialize];
}
return self;
}
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
if (self.text.length == 0 && self.placeholder) {
rect = [self placeholderRectForBounds:self.bounds];
UIFont *font = self.font ? self.font : self.typingAttributes[NSFontAttributeName];
// Draw the text
[self.placeholderTextColor set];
[self.placeholder drawInRect:rect withFont:font lineBreakMode:NSLineBreakByTruncatingTail alignment:self.textAlignment];
}
}
#pragma mark - Placeholder
- (CGRect)placeholderRectForBounds:(CGRect)bounds {
// Inset the rect
CGRect rect = UIEdgeInsetsInsetRect(bounds, self.contentInset);
if (self.typingAttributes) {
NSParagraphStyle *style = self.typingAttributes[NSParagraphStyleAttributeName];
if (style) {
rect.origin.x += style.headIndent;
rect.origin.y += style.firstLineHeadIndent;
}
}
return rect;
}
#pragma mark - Private
- (void)initialize {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChanged:) name:UITextViewTextDidChangeNotification object:self];
self.placeholderTextColor = [UIColor colorWithWhite:0.702f alpha:1.0f];
}
- (void)textChanged:(NSNotification *)notification {
[self setNeedsDisplay];
}
@end
它比其他的要简单得多,因为它不使用子视图(或有泄漏)。请随意使用。
更新11/10/11:它现在是文档化的,并支持在接口生成器中使用。
更新11/24/13:指向新的回购。
其他回答
我是这样做的:
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
你也可以创建一个新的类TextViewWithPlaceholder作为UITextView的子类。
(这段代码有点粗糙——但我认为它在正确的轨道上。)
@interface TextViewWithPlaceholder : UITextView
{
NSString *placeholderText; // make a property
UIColor *placeholderColor; // make a property
UIColor *normalTextColor; // cache text color here whenever you switch to the placeholderColor
}
- (void) setTextColor: (UIColor*) color
{
normalTextColor = color;
[super setTextColor: color];
}
- (void) updateForTextChange
{
if ([self.text length] == 0)
{
normalTextColor = self.textColor;
self.textColor = placeholderColor;
self.text = placeholderText;
}
else
{
self.textColor = normalTextColor;
}
}
在委托中,添加以下内容:
- (void)textViewDidChange:(UITextView *)textView
{
if ([textView respondsToSelector: @selector(updateForTextChange)])
{
[textView updateForTextChange];
}
}
这个帖子已经有了很多答案,但这里是我更喜欢的版本。
它扩展了现有的UITextView类,因此很容易重用,并且它不拦截像textViewDidChange这样的事件(这可能会破坏用户的代码,如果他们已经在其他地方拦截了这些事件)。
使用我的代码(如下所示),你可以很容易地添加一个占位符到任何你的UITextViews像这样:
self.textViewComments.placeholder = @"(Enter some comments here.)";
当你设置这个新的占位符值时,它会悄悄地在你的UITextView上添加一个UILabel,然后在必要时隐藏/显示它:
好的,要做这些改变,添加一个包含以下代码的"UITextViewHelper.h"文件:
// UITextViewHelper.h
// Created by Michael Gledhill on 13/02/15.
#import <Foundation/Foundation.h>
@interface UITextView (UITextViewHelper)
@property (nonatomic, strong) NSString* placeholder;
@property (nonatomic, strong) UILabel* placeholderLabel;
@property (nonatomic, strong) NSString* textValue;
-(void)checkIfNeedToDisplayPlaceholder;
@end
…和一个UITextViewHelper。M文件包含:
// UITextViewHelper.m
// Created by Michael Gledhill on 13/02/15.
//
// This UITextView category allows us to easily display a PlaceHolder string in our UITextView.
// The downside is that, your code needs to set the "textValue" rather than the "text" value to safely set the UITextView's text.
//
#import "UITextViewHelper.h"
#import <objc/runtime.h>
@implementation UITextView (UITextViewHelper)
#define UI_PLACEHOLDER_TEXT_COLOR [UIColor colorWithRed:170.0/255.0 green:170.0/255.0 blue:170.0/255.0 alpha:1.0]
@dynamic placeholder;
@dynamic placeholderLabel;
@dynamic textValue;
-(void)setTextValue:(NSString *)textValue
{
// Change the text of our UITextView, and check whether we need to display the placeholder.
self.text = textValue;
[self checkIfNeedToDisplayPlaceholder];
}
-(NSString*)textValue
{
return self.text;
}
-(void)checkIfNeedToDisplayPlaceholder
{
// If our UITextView is empty, display our Placeholder label (if we have one)
if (self.placeholderLabel == nil)
return;
self.placeholderLabel.hidden = (![self.text isEqualToString:@""]);
}
-(void)onTap
{
// When the user taps in our UITextView, we'll see if we need to remove the placeholder text.
[self checkIfNeedToDisplayPlaceholder];
// Make the onscreen keyboard appear.
[self becomeFirstResponder];
}
-(void)keyPressed:(NSNotification*)notification
{
// The user has just typed a character in our UITextView (or pressed the delete key).
// Do we need to display our Placeholder label ?
[self checkIfNeedToDisplayPlaceholder];
}
#pragma mark - Add a "placeHolder" string to the UITextView class
NSString const *kKeyPlaceHolder = @"kKeyPlaceHolder";
-(void)setPlaceholder:(NSString *)_placeholder
{
// Sets our "placeholder" text string, creates a new UILabel to contain it, and modifies our UITextView to cope with
// showing/hiding the UILabel when needed.
objc_setAssociatedObject(self, &kKeyPlaceHolder, (id)_placeholder, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
self.placeholderLabel = [[UILabel alloc] initWithFrame:self.frame];
self.placeholderLabel.numberOfLines = 1;
self.placeholderLabel.text = _placeholder;
self.placeholderLabel.textColor = UI_PLACEHOLDER_TEXT_COLOR;
self.placeholderLabel.backgroundColor = [UIColor clearColor];
self.placeholderLabel.userInteractionEnabled = true;
self.placeholderLabel.font = self.font;
[self addSubview:self.placeholderLabel];
[self.placeholderLabel sizeToFit];
// Whenever the user taps within the UITextView, we'll give the textview the focus, and hide the placeholder if necessary.
[self addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTap)]];
// Whenever the user types something in the UITextView, we'll see if we need to hide/show the placeholder label.
[[NSNotificationCenter defaultCenter] addObserver:self selector: @selector(keyPressed:) name:UITextViewTextDidChangeNotification object:nil];
[self checkIfNeedToDisplayPlaceholder];
}
-(NSString*)placeholder
{
// Returns our "placeholder" text string
return objc_getAssociatedObject(self, &kKeyPlaceHolder);
}
#pragma mark - Add a "UILabel" to this UITextView class
NSString const *kKeyLabel = @"kKeyLabel";
-(void)setPlaceholderLabel:(UILabel *)placeholderLabel
{
// Stores our new UILabel (which contains our placeholder string)
objc_setAssociatedObject(self, &kKeyLabel, (id)placeholderLabel, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[[NSNotificationCenter defaultCenter] addObserver:self selector: @selector(keyPressed:) name:UITextViewTextDidChangeNotification object:nil];
[self checkIfNeedToDisplayPlaceholder];
}
-(UILabel*)placeholderLabel
{
// Returns our new UILabel
return objc_getAssociatedObject(self, &kKeyLabel);
}
@end
是的,它有很多代码,但是一旦你把它添加到你的项目中,并包含了.h文件……
#import "UITextViewHelper.h"
...你可以很容易地在UITextViews中使用占位符。
不过有一个问题。
如果你这样做:
self.textViewComments.placeholder = @"(Enter some comments here.)";
self.textViewComments.text = @"Ooooh, hello there";
...占位符将出现在文本的顶部。设置文本值时,不会调用任何常规通知,因此我不知道如何调用我的函数来决定是否显示/隐藏占位符。
解决方案是设置textValue而不是text:
self.textViewComments.placeholder = @"(Enter some comments here.)";
self.textViewComments.textValue = @"Ooooh, hello there";
或者,您可以设置文本值,然后调用checkIfNeedToDisplayPlaceholder。
self.textViewComments.text = @"Ooooh, hello there";
[self.textViewComments checkIfNeedToDisplayPlaceholder];
我喜欢这样的解决方案,因为它们“填补了”苹果提供给我们的东西和我们(作为开发者)在应用程序中实际需要的东西之间的空白。只需编写一次此代码,将其添加到“helper”.m/.h文件库中,随着时间的推移,SDK实际上开始变得不那么令人沮丧。
(我写了一个类似的帮助添加一个“清除”按钮到我的UITextViews,另一个烦人的东西存在于UITextField但不在UITextView…)
我能够做添加一个“占位符”到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;
我猜这不是一个真正的占位符,因为你必须在写之前删除文本,但如果你想要一些更简单的东西,它可能会有帮助。
修改占位符文本颜色最简单的方法是通过XCode故事板接口构建器。选择感兴趣的UITextField并打开右侧的标识检查器。单击User Defined Runtime Attributes中的加号,并添加一个新行,其中Key Path为_placeholderLabel。输入颜色和值到你想要的颜色。