52

Is there any way to insert a placeholder in a UITextView similar to the UITextField? If yes, then please send me any link or any idea to implement this functionality.

Bartłomiej Semańczyk
  • 59,234
  • 49
  • 233
  • 358
Nikunj Jadav
  • 3,417
  • 7
  • 38
  • 54
  • How about using UITextView+Placeholder category? https://github.com/devxoul/UITextView-Placeholder – devxoul Aug 20 '15 at 11:01

6 Answers6

212

It is not possible to create placeholder in UITextView but you can generate effect like place holder by this.

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

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

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

OR you can add label in textview just like

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];

and set

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

- (void) textViewDidChange:(UITextView *)textView {
    if(![textView hasText]) {
        lbl.hidden = NO;
    }
    else {
        lbl.hidden = YES;
    }  
}
Kuldeep
  • 4,466
  • 8
  • 32
  • 59
PJR
  • 13,052
  • 13
  • 64
  • 104
  • 23
    it's nice and simple but textViewShouldBeginEditing will always erase all text - you might not want that when a user enters some text, leaves the text view, then comes back to edit again... *poof*. Could just add a check for the color though + only erase when it's grey. – n13 Feb 17 '12 at 07:37
  • What if I have more than one UITextView? – Dejell Sep 06 '12 at 14:59
  • @Odelya i had not face this problem , but i think you can do it by passing tag to them and change-show-hide labels according to tag condition.like if (txtview.tag == 1) { your code}. – PJR Sep 07 '12 at 05:18
  • 2
    never forget setting textview delegate methods to self, in ViewDidLoad insert this line commentTxtView.delegate=self; – AsifHabib Jan 21 '13 at 12:52
  • Nice solution I've changed a little the method - (BOOL) textViewShouldBeginEditing:(UITextView *)textView { if ([commentTxtView.text isEqualToString:@"Comment"]) { commentTxtView.text = @""; commentTxtView.textColor = [UIColor blackColor]; } return YES; } It helps when the TextView got the focus again. – Arkady Sep 14 '13 at 13:59
  • Really nice and helpful answer.+1. And @Dejel for multiple textfield use tag. Add tag to the label relative to textfield so you can find it using textfield tag, example.. textfield.tag=500 than give lbl.tag =1000, so in the textfield delegate method you can get the label using `UILabel *lbl = (UILabel *)[self.view viewWithTag:textView.tag+500];`, I have similar requirement like you and i have done it using this method. – Dilip Manek Oct 15 '13 at 07:44
  • You can use another UITextView instead of UILabel to match text insets of superview. – Uladzimir Aug 06 '15 at 09:54
18

Another easy solution is to just add a UILabel to your UITextView subview.

- (void)viewDidLoad
{
  [super viewDidLoad];

  // you might have to play around a little with numbers in CGRectMake method
  // they work fine with my settings
  placeholderLabel = [[UILabel alloc] initWithFrame:CGRectMake(10.0, 0.0, textView.frame.size.width - 20.0, 34.0)];
  [placeholderLabel setText:kDescriptionPlaceholder];
  // placeholderLabel is instance variable retained by view controller
  [placeholderLabel setBackgroundColor:[UIColor clearColor]];
  [placeholderLabel setFont:[challengeDescription font]];
  [placeholderLabel setTextColor:[UIColor lightGrayColor]];

  // textView is UITextView object you want add placeholder text to
  [textView addSubview:placeholderLabel];
}

- (void) textViewDidChange:(UITextView *)theTextView
{
  if(![textView hasText]) {
    [textView addSubview:placeholderLabel];
  } else if ([[textView subviews] containsObject:placeholderLabel]) {
    [placeholderLabel removeFromSuperview];
  }
}

- (void)textViewDidEndEditing:(UITextView *)theTextView
{
  if (![textView hasText]) {
    [textView addSubview:placeholderLabel];
  }
}

You can even add little animations to fade in/out the UILabel if that's your thing.

- (void) textViewDidChange:(UITextView *)theTextView
{
  if(![textView hasText]) {
    [textView addSubview:placeholderLabel];
    [UIView animateWithDuration:0.15 animations:^{
      placeholderLabel.alpha = 1.0;
    }];
  } else if ([[textView subviews] containsObject:placeholderLabel]) {

    [UIView animateWithDuration:0.15 animations:^{
      placeholderLabel.alpha = 0.0;
    } completion:^(BOOL finished) {
      [placeholderLabel removeFromSuperview];
    }];
  }
}


- (void)textViewDidEndEditing:(UITextView *)theTextView
{
  if (![textView hasText]) {
    [textView addSubview:placeholderLabel];
    [UIView animateWithDuration:0.15 animations:^{
      placeholderLabel.alpha = 1.0;
    }];
}
etolstoy
  • 1,798
  • 21
  • 33
jlajlar
  • 1,118
  • 11
  • 9
  • 1
    This may work, but it is against Apple's explicit recommendation: "Although it is technically possible to add subviews to the standard system controls—objects that inherit from UIControl—you should never customize them in this way." This is from https://developer.apple.com/library/ios/#documentation/WindowsViews/Conceptual/ViewPG_iPhoneOS/WindowsandViews/WindowsandViews.html#//apple_ref/doc/uid/TP40009503-CH2-SW26 in the section titled "Do Not Customize Controls by Embedding Subviews" – algal Oct 17 '12 at 14:28
  • Sure, I agree. But until apple implements this feature, this is a pretty good solution. – jlajlar Mar 04 '13 at 10:50
  • @algal So, what do you suggest? Isn't overriding `drawRect:` just as (or perhaps more) dangerous? – ma11hew28 Jul 09 '14 at 20:38
  • @MattDiPasquale The first of the two options in the selected answer seems to be clean, since it only adds logic to the view controller and only modifies the UITextView via its intended interface. – algal Jul 10 '14 at 04:21
  • @algal good call, but that solution isn't perfect: 1. It erases the placeholder text on `textViewShouldBeginEditing:` instead of `!textField.hasText()`. 2. It's not modular. Like, I'd rather have a custom subclass called `PlaceholderTextView` (e.g., that observes `UITextViewTextDidChangeNotification`) that I can just drop in and set it's `placeholder` property. – ma11hew28 Jul 11 '14 at 15:19
9

Another easy solution is set YES/NO for hidden properties of placeholderLabel

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

- (void) textViewDidChange:(UITextView *)textView
{
    if(![textView hasText]) {
        placeholderLabel.hidden = NO;
    }
    else{
        placeholderLabel.hidden = YES;
    }
}
Andrew Barber
  • 39,603
  • 20
  • 94
  • 123
MingSoft
  • 91
  • 1
  • 1
5
-(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
  // NSLog(@"REPlace %@ %d",text,range.location);
  if(range.location==0 && ![text isEqualToString:@""])
  {
    placeholderlbl.hidden = YES;
  }
  else if(range.location==0)
  {
    placeholderlbl.hidden = NO;
  }

  return YES;
}
j.w.r
  • 4,136
  • 2
  • 27
  • 29
swamy
  • 51
  • 1
  • 1
1

You can use as below function for making placeholder, Using thi you can set place holder on it..

[self addTextViewPlaceholder:self.txtvComment withPlaceholder:@"COMMENT"];

-(void) addTextViewPlaceholder:(UITextView*) tView withPlaceholder:(NSString*) placeholder
{
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(9,8,tView.bounds.size.width - 16,0)];
    label.lineBreakMode = UILineBreakModeWordWrap;
    label.numberOfLines = 0;
    label.font = [UIFont systemFontOfSize:13.0];
    label.backgroundColor = [UIColor clearColor];
    label.textColor = [UIColor colorWithRed:0.7 green:0.7 blue:0.7 alpha:1.0];

    label.text = placeholder;
    label.alpha = 1;
    label.tag = 999;
    [tView addSubview:label];
    [label sizeToFit];
    if(![tView.text isEqualToString:@""])
        [label setAlpha:0];
    [label release];
}

You can manage placeholder text using this..

- (void)textViewDidChange:(UITextView *)textView
{
    [self textChange:textView];
}

- (void)textChange:(UITextView *)textView
{
    if([textView.text length]>0)
        [[textView viewWithTag:999] setAlpha:0];
    else
        [[textView viewWithTag:999] setAlpha:1];
}
Meet Doshi
  • 4,241
  • 10
  • 40
  • 81
sinh99
  • 3,909
  • 32
  • 32
0

Another solution is to put a placeholder UITextView right on top of the actual UITextView. Give it the same frame. Set placeholderTextView.enabled = NO for the placeholder TextView.

Then, set the delegate for the normal textView only and define this UITextViewDelegate method:

- (void)textViewDidChange:(UITextView *)textView
{
    NSLog(@"textViewDidChange");

    if(self.textView.text.length == 0)
    {
        self.placeholderTextView.hidden = NO;
    }
    else
    {
        self.placeholderTextView.hidden = YES;
    }
}
ill_always_be_a_warriors
  • 1,546
  • 2
  • 17
  • 33