Question Espace réservé dans UITextView


Je fais une application qui utilise un UITextView. Maintenant je veux le UITextView avoir un espace réservé similaire à celui que vous pouvez définir pour un UITextField.

Est-ce que quelqu'un sait comment faire ça?


671


origine


Réponses:


J'ai apporté quelques modifications mineures à la solution de bcd pour permettre l'initialisation à partir d'un Xib fichier, l'habillage de texte et pour conserver la couleur d'arrière-plan. Espérons que cela sauvera les autres.

UIPlaceHolderTextView.h:

#import <Foundation/Foundation.h>
IB_DESIGNABLE
@interface UIPlaceHolderTextView : UITextView

@property (nonatomic, retain) IBInspectable NSString *placeholder;
@property (nonatomic, retain) IBInspectable 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

655



Facile, créez simplement un texte d'espace réservé dans UITextView en utilisant ce qui suit 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];
}

souvenez-vous juste de mettre myUITextView avec le texte exact sur la création, par ex.

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

et faire de la classe parent un UITextViewDelegate avant d'inclure ces méthodes, par ex.

@interface MyClass () <UITextViewDelegate>
@end

Code pour Swift 3.1

func textViewDidBeginEditing(_ textView: UITextView) 
{
    if (textView.text == "placeholder text here...")
    {
        textView.text = ""
        textView.textColor = .black
    }
    textView.becomeFirstResponder() //Optional
}

func textViewDidEndEditing(_ textView: UITextView)
{
    if (textView.text == "")
    {
        textView.text = "placeholder text here..."
        textView.textColor = .lightGray
    }
    textView.resignFirstResponder()
}

souvenez-vous juste de mettre myUITextView avec le texte exact sur la création, par ex.

 let myUITextView = UITextView.init()
 myUITextView.delegate = self
 myUITextView.text = "placeholder text here..."
 myUITextView.textColor = .lightGray

et faire de la classe parent un UITextViewDelegate avant d'inclure ces méthodes, par ex.

class MyClass: UITextViewDelegate
{

}

600



Je n'étais pas très content de l'une des solutions affichées car elles étaient un peu lourdes. L'ajout de vues à la vue n'est pas vraiment idéal drawRect:). Ils avaient tous les 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

C'est beaucoup plus simple que les autres, car il n'utilise pas de sous-vues (ou a des fuites). Sentez-vous libre de l'utiliser.

Mise à jour 11/10/11: Il est maintenant documenté et prend en charge l'utilisation dans Interface Builder.

Mise à jour du 24/11/13: Pointez sur le nouveau repo.


117



Ce que vous pouvez faire est de configurer la vue de texte avec une valeur initiale dans le text propriété, et changer la textColor à [UIColor grayColor] ou quelque chose de similaire. Ensuite, chaque fois que la vue de texte devient modifiable, effacez le texte et présentez un curseur, et si le champ de texte est à nouveau vide, replacez le texte de votre espace réservé. Changez la couleur pour [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.


52



Je me suis trouvé un moyen très facile d'imiter un place-titulaire

  1. dans la NIB ou le code définissez 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 textview à (exemple: "Foobar placeholder")
  4. implémenter: (BOOL) textViewShouldBeginEditing: (UITextView *) textView

Modifier:

Modification des instructions if pour comparer les balises plutôt que du texte. Si l'utilisateur a supprimé son texte, il a également été possible de supprimer accidentellement une partie du texte @"Foobar placeholder".Ceci signifiait que si l'utilisateur entrait à nouveau dans le textView, la méthode de délégation suivante, -(BOOL) textViewShouldBeginEditing:(UITextView *) textView, cela ne fonctionnerait pas comme prévu. J'ai essayé de comparer par la couleur du texte dans l'instruction if, mais j'ai trouvé que la couleur gris clair dans le constructeur de l'interface n'est pas la même que la couleur gris clair dans le code avec [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 la [longueur textView] == 0

MODIFIER:

Juste pour rendre la dernière partie plus claire - voici comment vous pouvez remettre le texte de l'espace réservé:

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

49



Vous pouvez définir l'étiquette sur le UITextViewpar

[UITextView addSubView:lblPlaceHoldaer];

et le cacher sur TextViewdidChange méthode.

C'est la manière simple et facile.


44



Si quelqu'un a besoin d'une solution pour Swift:

Ajouter UITextViewDelegate à votre classe

var placeHolderText = "Placeholder Text..."

override func viewDidLoad() {
    super.viewDidLoad()
    textView.delegate = self
}

func textViewShouldBeginEditing(textView: UITextView) -> Bool {

    self.textView.textColor = .black

    if(self.textView.text == placeHolderText) {
        self.textView.text = ""
    }

    return true
}

func textViewDidEndEditing(textView: UITextView) {
    if(textView.text == "") {
        self.textView.text = placeHolderText
        self.textView.textColor = .lightGray
    }
}

override func viewWillAppear(animated: Bool) {

    if(currentQuestion.answerDisplayValue == "") {
        self.textView.text = placeHolderText
        self.textView.textColor = .lightGray
    } else {
        self.textView.text = "xxx" // load default text / or stored 
        self.textView.textColor = .black
    }
}

40



Simple Swift 3 Solution

Ajouter UITextViewDelegate à ta classe

Ensemble yourTextView.delegate = self

Créer placeholderLabel et le positionner à l'intérieur yourTextView

Maintenant, juste animer placeholderLabel.alpha sur textViewDidChange:

  func textViewDidChange(_ textView: UITextView) {
    let newAlpha = textView.text.isEmpty ? 1.0 : 0.0
    if placeholderLabel.alpha != newAlpha {
      UIView.animate(withDuration: 0.3) {
        self.placeholderLabel.alpha = newAlpha
      }
    }
  }

vous pourriez avoir à jouer avec placeholderLabel position pour le configurer à droite, mais cela ne devrait pas être trop dur


37



J'ai étendu la réponse de KmKndy, de sorte que l'espace réservé reste visible jusqu'à ce que l'utilisateur commence à éditer le UITextView plutôt que de simplement appuyer dessus. Cela reflète la fonctionnalité des applications Twitter et Facebook. Ma solution ne nécessite pas de sous-classe et fonctionne si l'utilisateur tape directement ou colle du texte!

Example of Placeholder  Twitter App

- (void)textViewDidChangeSelection:(UITextView *)textView{
    if ([textView.text isEqualToString:@"What's happening?"] && [textView.textColor isEqual:[UIColor lightGrayColor]])[textView setSelectedRange:NSMakeRange(0, 0)];

}

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

    [textView setSelectedRange:NSMakeRange(0, 0)];
}

- (void)textViewDidChange:(UITextView *)textView
{
    if (textView.text.length != 0 && [[textView.text substringFromIndex:1] isEqualToString:@"What's happening?"] && [textView.textColor isEqual:[UIColor lightGrayColor]]){
        textView.text = [textView.text substringToIndex:1];
        textView.textColor = [UIColor blackColor]; //optional

    }
    else if(textView.text.length == 0){
        textView.text = @"What's happening?";
        textView.textColor = [UIColor lightGrayColor];
        [textView setSelectedRange:NSMakeRange(0, 0)];
    }
}

- (void)textViewDidEndEditing:(UITextView *)textView
{
    if ([textView.text isEqualToString:@""]) {
        textView.text = @"What's happening?";
        textView.textColor = [UIColor lightGrayColor]; //optional
    }
    [textView resignFirstResponder];
}

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{
    if (textView.text.length > 1 && [textView.text isEqualToString:@"What's happening?"]) {
         textView.text = @"";
         textView.textColor = [UIColor blackColor];
    }

    return YES;
}

N'oubliez pas de définir myUITextView avec le texte exact lors de la création, par ex.

UITextView *myUITextView = [[UITextView alloc] init];
myUITextView.delegate = self;
myUITextView.text = @"What's happening?";
myUITextView.textColor = [UIColor lightGrayColor]; //optional

et faites de la classe parent un délégué UITextView avant d'inclure ces méthodes, par exemple.

@interface MyClass () <UITextViewDelegate>
@end

22



Je recommande d'utiliser SZTextView.

https://github.com/glaszig/SZTextView

Ajouter votre défaut UITextView de storyboard puis changez sa classe personnalisée pour SZTextView comme ci-dessous

enter image description here

Ensuite, vous verrez deux nouvelles options dans le Attribute Inspector 

enter image description here


20