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

如何做到这一点?


当前回答

看一下UTPlaceholderTextView。

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

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

其他回答

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

这里我取

UILabel * lbl;

然后在。m中viewDidLoad下声明它

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占位符准备好了!

我修改了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;
}

记住在可能改变字体和其他可能影响它们的东西的方法中设置_placeholderattributes = nil。如果没有问题的话,您可能还想跳过属性字典的“惰性”创建。

编辑:

如果你想让占位符在自动布局动画之后看起来更好,记得在setBounds的重写版本中调用setNeedsDisplay。

你也可以创建一个新的类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];
    }

}

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

让我们借用UITextField中的占位符。

Set up a textField and set its text transparent. 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]; Set textView's delegate and synchronize the textField and textView. yourTextView.delegate = self; then - (void)textViewDidChange:(UITextView *)textView { self.placeholderTextField.text = textView.text; } That's all.

After looking through (and trying out) most of the proposed solutions to this seemingly obvious - but missing - feature of UITextView, the 'best' closest I found was that from BobDickinson. But I didnt like having to resort to a whole new subclass [I prefer drop-in categories for such simple functional additions], nor that it intercepted UITextViewDelegate methods, which is probably going to mess up your existing UITextView handling code. So here's my take on a drop-in category that'll work on any existing UITextView instance...

#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";

它通过添加一个UITextField -在正确的位置-在你的UITextView后面,并利用它的占位符代替(因此你不必担心得到正确的颜色等),然后监听通知,每当你的UITextView被改变显示/隐藏这个UITextField(因此它不会干扰你现有的UITextViewDelegate调用)。这里面没有什么神奇的数字……: -)

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

改编自BobDickinson的斯威夫特回答。