749 votes

Placeholder dans UITextView

Je réalise une application qui utilise un UITextView . Maintenant, je veux que le UITextView pour avoir un caractère de remplacement similaire à celui que vous pouvez définir pour une UITextField .

Quelqu'un sait-il comment faire ?

676voto

Jason George Points 5507

J'ai apporté quelques modifications mineures à la solution de bcd pour permettre l'initialisation à partir d'un fichier xib, l'habillage du texte et le maintien de la couleur de fond. J'espère que cela évitera à d'autres de s'embêter.

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

645voto

CmKndy Points 1121

Pour simplifier, il suffit de créer un texte de remplacement dans UITextView en utilisant les éléments suivants UITextViewDelegate méthodes :

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

n'oubliez pas de définir myUITextView avec le texte exact sur la création, par exemple

UITextView *myUITextView = [[UITextView alloc] init];
myUITextView.delegate = self;
myUITextView.text = @"placeholder text here...";
myUITextView.textColor = [UIColor lightGrayColor]; //optional

et faire de la classe mère une UITextViewDelegate avant d'inclure ces méthodes, par exemple

@interface MyClass () <UITextViewDelegate>
@end

119voto

Sam Soffes Points 8034

Je n'étais pas très satisfait des solutions proposées, car elles étaient un peu lourdes. Ajouter des vues à la vue n'est pas vraiment l'idéal (surtout dans le cas de drawRect: ). Ils avaient tous deux des fuites, ce qui n'est pas acceptable non plus.

Voici ma solution : 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

Il est beaucoup plus simple que les autres, car il n'utilise pas de sous-vues (ou n'a pas de fuites). N'hésitez pas à l'utiliser.

Mise à jour 11/10/11 : Il est maintenant documenté et peut être utilisé dans Interface Builder.

Mise à jour 24/11/13 : Pointer vers le nouveau dépôt.

56voto

vdevos Points 415

J'ai trouvé un moyen très facile d'imiter un marqueur de place.

  1. dans le NIB ou le code, définissez le textColor de votre textView à lightGrayColor (la plupart du temps).
  2. Assurez-vous que le délégué de votre textView est lié au propriétaire du fichier et implémentez UITextViewDelegate dans votre fichier d'en-tête.
  3. définir le texte par défaut de votre fenêtre de texte (exemple : "Foobar placeholder")
  4. implémenter : (BOOL) textViewShouldBeginEditing :(UITextView *)textView

Edit :

Modification des instructions if pour comparer les balises plutôt que le texte. Si l'utilisateur supprimait son texte, il était possible de supprimer accidentellement une partie du substitut. @"Foobar placeholder" Cela signifie que si l'utilisateur entre à nouveau dans l'affichage du texte, la méthode déléguée suivante sera appliquée, -(BOOL) textViewShouldBeginEditing:(UITextView *) textView mais cela ne fonctionne pas comme prévu. J'ai essayé de comparer la couleur du texte dans l'instruction if, mais j'ai constaté que la couleur gris clair définie dans le constructeur d'interface n'est pas la même que la couleur gris clair définie dans le code avec la fonction [UIColor lightGreyColor]

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

Il est également possible de réinitialiser le texte de l'espace réservé lorsque le clavier revient et que la [longueur de la fenêtre de texte] == 0.

EDIT :

Pour que la dernière partie soit plus claire, voici comment vous pouvez rétablir le texte de remplacement :

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

52voto

Tim Points 33042

Ce que vous pouvez faire, c'est configurer la vue texte avec une valeur initiale dans le champ text et modifiez la propriété textColor à [UIColor grayColor] ou quelque chose de similaire. Ensuite, chaque fois que la vue du texte devient modifiable, effacez le texte et présentez un curseur, et si le champ de texte est à nouveau vide, remettez votre texte de remplacement. Changez la couleur en [UIColor blackColor] le cas échéant.

Ce n'est pas exactement la même chose que la fonctionnalité d'espace réservé dans un UITextField, mais c'est proche.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X