Hi all!
I'm making an application which uses an UITextView. Now I want the UITextView to have a placeholder similar to the one you can set for an UITextField.
Does anyone know how to do this?
Thanks in advance.
Hi all!
I'm making an application which uses an UITextView. Now I want the UITextView to have a placeholder similar to the one you can set for an UITextField.
Does anyone know how to do this?
Thanks in advance.
What you can do is set up the text view with some initial value in the text
property, and change the textColor
to [UIColor grayColor]
or something similar. Then, whenever the text view becomes editable, clear the text and present a cursor, and if the text field is ever empty again, put your placeholder text back. Change the color to [UIColor blackColor]
as appropriate.
It's not exactly the same as the placeholder functionality in a UITextField, but it's close.
You could also create a new class TextViewWithPlaceholder as a subclass of UITextView.
(This code is kind of rough -- but I think it's on the right track.)
@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;
}
}
In your delegate, add this:
- (void)textViewDidChange:(UITextView *)textView
{
if ([textView respondsToSelector: @selector(updateForTextChange)])
{
[textView updateForTextChange];
}
}
this is how I did it:
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
This is great, and very helpful, but there are a couple other things missing from UITextView that would be very handy as well: the borderStyle property, to make it look more like a UITextField, and the clearButtonMode property, to get the little clear text button overlayed.
Does anybody have sample code to add those two features as well?
Jason and bcd, thanks so much for this. Worked perfectly for me. I had simply replace UITextView with your class and everything else just fit in.
hi friend
you can set lable on the UITextView by [UITextView addSubView:lblPlaceHoldaer];
and hide it on TextViewdidChange method
it is the simple & easy way.....
Yakub Moriss
From Ahmedabad(Guj-India)
Very, very nice description. Thanks so much. I had exactly the same idea myself but this saved me about 30 minutes of fluffing around getting it working.
I agree. A borderStyle on a UITextView would be wonderful. The UITextView interface is somewhat light on useful functionality. For a curved border I'd suggest you just resort to photoshop or see if you can put a disabled UITextField behind the UITextView and make the textview transparent.
I wasn't too happy with any of the solutions posted as they were a bit heavy. Adding views to the view isn't really ideal (especially in drawRect:
). They both had leaks, which isn't acceptable either.
Here is my solution: SSTextView
SSTextView.h
//
// SSTextView.h
// SSToolkit
//
// Created by Sam Soffes on 8/18/10.
// Copyright 2010 Sam Soffes. All rights reserved.
//
@interface SSTextView : UITextView {
NSString *_placeholder;
UIColor *_placeholderColor;
BOOL _shouldDrawPlaceholder;
}
@property (nonatomic, retain) NSString *placeholder;
@property (nonatomic, retain) UIColor *placeholderColor;
@end
SSTextView.m
//
// SSTextView.m
// SSToolkit
//
// Created by Sam Soffes on 8/18/10.
// Copyright 2010 Sam Soffes. All rights reserved.
//
#import "SSTextView.h"
@interface SSTextView (PrivateMethods)
- (void)_updateShouldDrawPlaceholder;
- (void)_textChanged:(NSNotification *)notification;
@end
@implementation SSTextView
@synthesize placeholder = _placeholder;
@synthesize placeholderColor = _placeholderColor;
#pragma mark NSObject
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self name:UITextViewTextDidChangeNotification object:self];
[_placeholder release];
[_placeholderColor release];
[super dealloc];
}
#pragma mark UIView
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_textChanged:) name:UITextViewTextDidChangeNotification object:self];
self.placeholderColor = [UIColor lightGrayColor];
_shouldDrawPlaceholder = NO;
}
return self;
}
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
if (_shouldDrawPlaceholder) {
[_placeholderColor set];
[_placeholder drawInRect:CGRectMake(8.0, 8.0, self.frame.size.width - 16.0, self.frame.size.height - 16.0) withFont:self.font];
}
}
#pragma mark Setters
- (void)setText:(NSString *)string {
[super setText:string];
[self _updateShouldDrawPlaceholder];
}
- (void)setPlaceholder:(NSString *)string {
if ([string isEqual:_placeholder]) {
return;
}
[_placeholder release];
_placeholder = [string retain];
[self _updateShouldDrawPlaceholder];
}
#pragma mark Private Methods
- (void)_updateShouldDrawPlaceholder {
BOOL prev = _shouldDrawPlaceholder;
_shouldDrawPlaceholder = self.placeholder && self.placeholderColor && self.text.length == 0;
if (prev != _shouldDrawPlaceholder) {
[self setNeedsDisplay];
}
}
- (void)_textChanged:(NSNotification *)notificaiton {
[self _updateShouldDrawPlaceholder];
}
@end
It's a lot simpler than the others, as it doesn't use subviews (or have leaks). Feel free to use it.