ios objective-c cocoa-touch uitextview placeholder

ios - Placeholder en UITextView



objective-c cocoa-touch (30)

Mi aplicación utiliza un UITextView . Ahora quiero que el UITextView tenga un marcador de posición similar al que puede establecer para un UITextField .

¿Como hacer esto?


A continuación se muestra un puerto Swift del código de ObjC "SAMTextView" publicado como una de las primeras respuestas a la pregunta. Lo probé en iOS 8. Ajusté un par de cosas, incluido el desplazamiento de límites para la colocación del texto del marcador de posición, ya que el original era demasiado alto y demasiado a la derecha (se utilizó la sugerencia en uno de los comentarios de esa publicación).

Sé que hay muchas soluciones simples, pero me gusta el enfoque de subclasificar UITextView porque es reutilizable y no tengo que desordenar las clases utilizando los mecanismos.

Swift 2.2:

import UIKit class PlaceholderTextView: UITextView { @IBInspectable var placeholderColor: UIColor = UIColor.lightGrayColor() @IBInspectable var placeholderText: String = "" override var font: UIFont? { didSet { setNeedsDisplay() } } override var contentInset: UIEdgeInsets { didSet { setNeedsDisplay() } } override var textAlignment: NSTextAlignment { didSet { setNeedsDisplay() } } override var text: String? { didSet { setNeedsDisplay() } } override var attributedText: NSAttributedString? { didSet { setNeedsDisplay() } } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setUp() } override init(frame: CGRect, textContainer: NSTextContainer?) { super.init(frame: frame, textContainer: textContainer) } private func setUp() { NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(PlaceholderTextView.textChanged(_:)), name: UITextViewTextDidChangeNotification, object: self) } func textChanged(notification: NSNotification) { setNeedsDisplay() } func placeholderRectForBounds(bounds: CGRect) -> CGRect { var x = contentInset.left + 4.0 var y = contentInset.top + 9.0 let w = frame.size.width - contentInset.left - contentInset.right - 16.0 let h = frame.size.height - contentInset.top - contentInset.bottom - 16.0 if let style = self.typingAttributes[NSParagraphStyleAttributeName] as? NSParagraphStyle { x += style.headIndent y += style.firstLineHeadIndent } return CGRect(x: x, y: y, width: w, height: h) } override func drawRect(rect: CGRect) { if text!.isEmpty && !placeholderText.isEmpty { let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.alignment = textAlignment let attributes: [ String: AnyObject ] = [ NSFontAttributeName : font!, NSForegroundColorAttributeName : placeholderColor, NSParagraphStyleAttributeName : paragraphStyle] placeholderText.drawInRect(placeholderRectForBounds(bounds), withAttributes: attributes) } super.drawRect(rect) } }

Swift 4.2:

import UIKit class PlaceholderTextView: UITextView { @IBInspectable var placeholderColor: UIColor = UIColor.lightGray @IBInspectable var placeholderText: String = "" override var font: UIFont? { didSet { setNeedsDisplay() } } override var contentInset: UIEdgeInsets { didSet { setNeedsDisplay() } } override var textAlignment: NSTextAlignment { didSet { setNeedsDisplay() } } override var text: String? { didSet { setNeedsDisplay() } } override var attributedText: NSAttributedString? { didSet { setNeedsDisplay() } } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setUp() } override init(frame: CGRect, textContainer: NSTextContainer?) { super.init(frame: frame, textContainer: textContainer) } private func setUp() { NotificationCenter.default.addObserver(self, selector: #selector(self.textChanged(notification:)), name: Notification.Name("UITextViewTextDidChangeNotification"), object: nil) } @objc func textChanged(notification: NSNotification) { setNeedsDisplay() } func placeholderRectForBounds(bounds: CGRect) -> CGRect { var x = contentInset.left + 4.0 var y = contentInset.top + 9.0 let w = frame.size.width - contentInset.left - contentInset.right - 16.0 let h = frame.size.height - contentInset.top - contentInset.bottom - 16.0 if let style = self.typingAttributes[NSAttributedString.Key.paragraphStyle] as? NSParagraphStyle { x += style.headIndent y += style.firstLineHeadIndent } return CGRect(x: x, y: y, width: w, height: h) } override func draw(_ rect: CGRect) { if text!.isEmpty && !placeholderText.isEmpty { let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.alignment = textAlignment let attributes: [NSAttributedString.Key: Any] = [ NSAttributedString.Key(rawValue: NSAttributedString.Key.font.rawValue) : font!, NSAttributedString.Key(rawValue: NSAttributedString.Key.foregroundColor.rawValue) : placeholderColor, NSAttributedString.Key(rawValue: NSAttributedString.Key.paragraphStyle.rawValue) : paragraphStyle] placeholderText.draw(in: placeholderRectForBounds(bounds: bounds), withAttributes: attributes) } super.draw(rect) } }


Aquí hay una solución mucho más sencilla que se comporta exactamente como el marcador de posición de UITextField pero que no requiere dibujar vistas personalizadas o renunciar al primer respondedor.

- (void) textViewDidChange:(UITextView *)textView{ if (textView.text.length == 0){ textView.textColor = [UIColor lightGrayColor]; textView.text = placeholderText; [textView setSelectedRange:NSMakeRange(0, 0)]; isPlaceholder = YES; } else if (isPlaceholder && ![textView.text isEqualToString:placeholderText]) { textView.text = [textView.text substringToIndex:1]; textView.textColor = [UIColor blackColor]; isPlaceholder = NO; } }

(la segunda verificación en el estado else si es para el caso donde no se ingresa nada y el usuario presiona la tecla de retroceso)

Solo configura tu clase como UITextViewDelegate. En viewDidLoad debes inicializar como

- (void) viewDidLoad{ // initialize placeholder text placeholderText = @"some placeholder"; isPlaceholder = YES; self.someTextView.text = placeholderText; self.someTextView.textColor = [UIColor lightGrayColor]; [self.someTextView setSelectedRange:NSMakeRange(0, 0)]; // assign UITextViewDelegate self.someTextView.delegate = self; }


Así es como lo hice.

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


De manera sencilla, simplemente cree un texto de marcador de posición en UITextView utilizando los siguientes métodos de UITextViewDelegate :

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

solo recuerda configurar myUITextView con el texto exacto en la creación, por ejemplo

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

y haga que la clase padre sea UITextViewDelegate antes de incluir estos métodos, por ejemplo,

@interface MyClass () <UITextViewDelegate> @end

Código para Swift 3.1

func textViewDidBeginEditing(_ textView: UITextView) { if (textView.text == "placeholder text here..." && textView.textColor == .lightGray) { 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() }

solo recuerda configurar myUITextView con el texto exacto en la creación, por ejemplo

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

y haga que la clase padre sea UITextViewDelegate antes de incluir estos métodos, por ejemplo,

class MyClass: UITextViewDelegate { }


Extendí la respuesta de KmKndy, para que el marcador de posición permanezca visible hasta que el usuario comience a editar el UITextView lugar de solo UITextView . Esto refleja la funcionalidad de las aplicaciones de Twitter y Facebook. ¡Mi solución no requiere subclases y funciona si el usuario escribe directamente o pega texto!

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

solo recuerda configurar myUITextView con el texto exacto en la creación, por ejemplo

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

y haga que la clase padre sea un delegado de UITextView antes de incluir estos métodos, por ejemplo,

@interface MyClass () <UITextViewDelegate> @end


Hice algunas modificaciones menores a la solución de bcd para permitir la inicialización de un archivo Xib , el Xib texto y mantener el color de fondo. Ojalá le salve a los demás el problema.

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


Hola, puede usar IQTextView disponible en IQKeyboard Manager. Es fácil de usar e integrar, simplemente configure la clase de su vista de texto en IQTextView y puede usar su propiedad para configurar la etiqueta del marcador de posición con el color que desee. Puedes descargar la biblioteca desde IQKeyboardManager

O puedes instalarlo desde cocoapods.


Lo que puede hacer es configurar la vista de texto con algún valor inicial en la propiedad de text , y cambiar el textColor del textColor a [UIColor grayColor] o algo similar. Luego, cuando la vista de texto sea editable, borre el texto y presente un cursor, y si el campo de texto vuelve a estar vacío, vuelva a colocar el texto de su marcador de posición. Cambie el color a [UIColor blackColor] según corresponda.

No es exactamente lo mismo que la funcionalidad de marcador de posición en un UITextField, pero está cerca.


Me encontré con una manera muy fácil de imitar a un marcador de posición.

  1. en el NIB o el código establece el textColor de tu textView en lightGrayColor (la mayoría de las veces)
  2. asegúrese de que el delegado de su textView esté vinculado al propietario del archivo e implemente UITextViewDelegate en su archivo de encabezado
  3. establezca el texto predeterminado de su vista de texto en (ejemplo: "marcador de posición Foobar")
  4. implementar: (BOOL) textViewShouldBeginEditing: (UITextView *) textView

Editar:

Se modificaron las instrucciones if para comparar etiquetas en lugar de texto. Si el usuario eliminó su texto, también fue posible eliminar accidentalmente una parte del @"Foobar placeholder" . Esto significaba que si el usuario volvía a ingresar el texto. Vea el siguiente método de delegado, -(BOOL) textViewShouldBeginEditing:(UITextView *) textView , no funcionaría como se esperaba. Intenté comparar por el color del texto en la instrucción if, pero descubrí que el conjunto de colores gris claro en el generador de interfaces no es el mismo que el conjunto de colores gris claro en el código con [UIColor lightGreyColor]

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

También es posible restablecer el texto del marcador de posición cuando el teclado regresa y el [textView length] == 0

EDITAR:

Solo para aclarar la última parte, aquí es cómo puede restablecer el texto del marcador de posición:

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


No estaba muy contento con ninguna de las soluciones publicadas, ya que eran un poco pesadas. Agregar vistas a la vista no es realmente ideal (especialmente en drawRect: . Ambos tenían filtraciones, lo cual tampoco es aceptable.

Aquí está mi solución: 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

Es mucho más simple que los demás, ya que no utiliza subvistas (o tiene fugas). Sientase libre de usarlo.

Actualización 11/10/11: ahora está documentado y es compatible con el uso en Interface Builder.

Actualización 11/24/13: apunta a nuevo repositorio.


Perdón por agregar otra respuesta, pero acabo de sacar algo como esto y esto creó el tipo de marcador de posición más cercano a UITextField.

Espero que esto ayude a alguien.

-(void)textViewDidChange:(UITextView *)textView{ if(textView.textColor == [UIColor lightGrayColor]){ textView.textColor = [UIColor blackColor]; // look at the comment section in this answer textView.text = [textView.text substringToIndex: 0];// look at the comment section in this answer }else if(textView.text.length == 0){ textView.text = @"This is some placeholder text."; textView.textColor = [UIColor lightGrayColor]; textView.selectedRange = NSMakeRange(0, 0); } } -(void)textViewDidChangeSelection:(UITextView *)textView{ if(textView.textColor == [UIColor lightGrayColor] && (textView.selectedRange.location != 0 || textView.selectedRange.length != 0)){ textView.selectedRange = NSMakeRange(0, 0); } }


Puede establecer la etiqueta en el UITextView por

[UITextView addSubView:lblPlaceHoldaer];

y esconderlo en el método TextViewdidChange .

Esta es la manera simple y fácil.


Recomiendo usar SZTextView .

https://github.com/glaszig/SZTextView

Agregue su UITextView predeterminado desde el storyboard y luego cambie su clase personalizada a SZTextView como a continuación 👇👇👇👇

Luego verá dos nuevas opciones en el Attribute Inspector 👇👇👇👇


Si alguien necesita una solución para Swift:

Agregue UITextViewDelegate a su clase

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 } }


Simple solución Swift 3

Agregue UITextViewDelegate a su clase

Establezca yourTextView.delegate = self

Cree un placeholderLabel y yourTextView dentro de yourTextView

Ahora solo anima placeholderLabel.alpha en textViewDidChange :

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

puede que tengas que jugar con la placeholderLabel para configurarlo correctamente, pero eso no debería ser demasiado difícil



Este hilo ha tenido muchas respuestas, pero aquí está la versión que prefiero.

Se extiende el vigente UITextViewclase para que sea fácilmente reutilizable, y no interceptar los eventos como textViewDidChange(lo que podría romper el código del usuario, si ya estaban interceptando estos eventos en otros lugares).

Al usar mi código (que se muestra a continuación), puede agregar fácilmente un marcador de posición a cualquiera de sus "me UITextViewsgusta":

self.textViewComments.placeholder = @"(Enter some comments here.)";

Cuando establece este nuevo valor de marcador de posición, agrega silenciosamente un UILabelencima de su UITextView, luego lo oculta / muestra según sea necesario:

Bien, para realizar estos cambios, agregue un archivo "UITextViewHelper.h" que contenga este código:

// UITextViewHelper.h // Created by Michael Gledhill on 13/02/15. #import <Foundation/Foundation.h> @interface UITextView (UITextViewHelper) @property (nonatomic, strong) NSString* placeholder; @property (nonatomic, strong) UILabel* placeholderLabel; @property (nonatomic, strong) NSString* textValue; -(void)checkIfNeedToDisplayPlaceholder; @end

... y un archivo UITextViewHelper.m que contiene esto:

// UITextViewHelper.m // Created by Michael Gledhill on 13/02/15. // // This UITextView category allows us to easily display a PlaceHolder string in our UITextView. // The downside is that, your code needs to set the "textValue" rather than the "text" value to safely set the UITextView''s text. // #import "UITextViewHelper.h" #import <objc/runtime.h> @implementation UITextView (UITextViewHelper) #define UI_PLACEHOLDER_TEXT_COLOR [UIColor colorWithRed:170.0/255.0 green:170.0/255.0 blue:170.0/255.0 alpha:1.0] @dynamic placeholder; @dynamic placeholderLabel; @dynamic textValue; -(void)setTextValue:(NSString *)textValue { // Change the text of our UITextView, and check whether we need to display the placeholder. self.text = textValue; [self checkIfNeedToDisplayPlaceholder]; } -(NSString*)textValue { return self.text; } -(void)checkIfNeedToDisplayPlaceholder { // If our UITextView is empty, display our Placeholder label (if we have one) if (self.placeholderLabel == nil) return; self.placeholderLabel.hidden = (![self.text isEqualToString:@""]); } -(void)onTap { // When the user taps in our UITextView, we''ll see if we need to remove the placeholder text. [self checkIfNeedToDisplayPlaceholder]; // Make the onscreen keyboard appear. [self becomeFirstResponder]; } -(void)keyPressed:(NSNotification*)notification { // The user has just typed a character in our UITextView (or pressed the delete key). // Do we need to display our Placeholder label ? [self checkIfNeedToDisplayPlaceholder]; } #pragma mark - Add a "placeHolder" string to the UITextView class NSString const *kKeyPlaceHolder = @"kKeyPlaceHolder"; -(void)setPlaceholder:(NSString *)_placeholder { // Sets our "placeholder" text string, creates a new UILabel to contain it, and modifies our UITextView to cope with // showing/hiding the UILabel when needed. objc_setAssociatedObject(self, &kKeyPlaceHolder, (id)_placeholder, OBJC_ASSOCIATION_RETAIN_NONATOMIC); self.placeholderLabel = [[UILabel alloc] initWithFrame:self.frame]; self.placeholderLabel.numberOfLines = 1; self.placeholderLabel.text = _placeholder; self.placeholderLabel.textColor = UI_PLACEHOLDER_TEXT_COLOR; self.placeholderLabel.backgroundColor = [UIColor clearColor]; self.placeholderLabel.userInteractionEnabled = true; self.placeholderLabel.font = self.font; [self addSubview:self.placeholderLabel]; [self.placeholderLabel sizeToFit]; // Whenever the user taps within the UITextView, we''ll give the textview the focus, and hide the placeholder if necessary. [self addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTap)]]; // Whenever the user types something in the UITextView, we''ll see if we need to hide/show the placeholder label. [[NSNotificationCenter defaultCenter] addObserver:self selector: @selector(keyPressed:) name:UITextViewTextDidChangeNotification object:nil]; [self checkIfNeedToDisplayPlaceholder]; } -(NSString*)placeholder { // Returns our "placeholder" text string return objc_getAssociatedObject(self, &kKeyPlaceHolder); } #pragma mark - Add a "UILabel" to this UITextView class NSString const *kKeyLabel = @"kKeyLabel"; -(void)setPlaceholderLabel:(UILabel *)placeholderLabel { // Stores our new UILabel (which contains our placeholder string) objc_setAssociatedObject(self, &kKeyLabel, (id)placeholderLabel, OBJC_ASSOCIATION_RETAIN_NONATOMIC); [[NSNotificationCenter defaultCenter] addObserver:self selector: @selector(keyPressed:) name:UITextViewTextDidChangeNotification object:nil]; [self checkIfNeedToDisplayPlaceholder]; } -(UILabel*)placeholderLabel { // Returns our new UILabel return objc_getAssociatedObject(self, &kKeyLabel); } @end

Sí, es un montón de código, pero una vez que lo hayas agregado a tu proyecto e incluido el archivo .h ...

#import "UITextViewHelper.h"

... puedes usar fácilmente marcadores de posición en UITextViews.

Sin embargo, hay uno que tiene

Si haces esto:

self.textViewComments.placeholder = @"(Enter some comments here.)"; self.textViewComments.text = @"Ooooh, hello there";

... el marcador de posición aparecerá en la parte superior del texto. Cuando establece el textvalor, no se llama ninguna de las notificaciones regulares, por lo que no pude averiguar cómo llamar a mi función para decidir si mostrar / ocultar el marcador de posición.

La solución es establecer el en textValuelugar de text:

self.textViewComments.placeholder = @"(Enter some comments here.)"; self.textViewComments.textValue = @"Ooooh, hello there";

Alternativamente, puede establecer el textvalor, luego llamar checkIfNeedToDisplayPlaceholder.

self.textViewComments.text = @"Ooooh, hello there"; [self.textViewComments checkIfNeedToDisplayPlaceholder];

Me gustan las soluciones como esta, ya que "llenan el vacío" entre lo que Apple nos brinda y lo que nosotros (como desarrolladores) realmente necesitamos en nuestras aplicaciones. Usted escribe este código una vez, lo agrega a su biblioteca de archivos .m / .h "de ayuda" y, con el tiempo, el SDK comienza a volverse menos frustrante.

(Escribí un ayudante similar para agregar un botón "borrar" a mi UITextViews, otra cosa que molesta existe UITextFieldpero no en UITextView...)


Esto imita el marcador de posición de UITextField a la perfección, donde el texto del marcador de posición permanece hasta que realmente escribe algo.

private let placeholder = "Type here" @IBOutlet weak var textView: UITextView! { didSet { textView.textColor = UIColor.lightGray textView.text = placeholder textView.selectedRange = NSRange(location: 0, length: 0) } } extension ViewController: UITextViewDelegate { func textViewDidChangeSelection(_ textView: UITextView) { // Move cursor to beginning on first tap if textView.text == placeholder { textView.selectedRange = NSRange(location: 0, length: 0) } } func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { if textView.text == placeholder && !text.isEmpty { textView.text = nil textView.textColor = UIColor.black textView.selectedRange = NSRange(location: 0, length: 0) } return true } func textViewDidChange(_ textView: UITextView) { if textView.text.isEmpty { textView.textColor = UIColor.lightGray textView.text = placeholder } } }


He modificado la implementación de Sam Soffes para que funcione con 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; }

Recuerde establecer _placeholderAttribues = nilmétodos que puedan cambiar la fuente y otros temas que puedan afectarlos. También es posible que desee omitir la creación "perezosa" del diccionario de atributos si eso no le molesta.

EDITAR:

Recuerde llamar a setNeedsDisplay en una versión anulada de setBounds si desea que el marcador de posición se vea bien después de las animaciones de autolayout y similares.


No es posible crear un marcador de posición en UITextView pero puede generar un efecto como un marcador de posición de esta manera.

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

O puede agregar etiqueta en vista de texto al igual que

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

y establecer

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


Primero toma una etiqueta en el archivo .h.

Aqui llevo

UILabel * lbl;

Luego en .m bajo viewDidLoad declararlo

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 es mi TextView.

Ahora declara

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

¡Y tu marcador de posición Textview está listo!


Recomiendo usar pod ''UITextView + Placeholder''

pod ''UITextView+Placeholder''

en tu código

#import "UITextView+Placeholder.h" //// UITextView *textView = [[UITextView alloc] init]; textView.placeholder = @"How are you?"; textView.placeholderColor = [UIColor lightGrayColor];


También puede crear una nueva clase TextViewWithPlaceholder como una subclase de UITextView.

(Este código es bastante rudo, pero creo que va por el buen camino).

@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; } }

En su delegado, agregue esto:

- (void)textViewDidChange:(UITextView *)textView { if ([textView respondsToSelector: @selector(updateForTextChange)]) { [textView updateForTextChange]; } }


Una forma sencilla de usar esto dentro de alguna línea de código:

Lleve una etiqueta hasta UITextView en .nib conectando esta etiqueta a su código, Después de eso.

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{ if (range.location>0 || text.length!=0) { placeholderLabel1.hidden = YES; }else{ placeholderLabel1.hidden = NO; } return YES; }


Vamos a hacerlo fácil

Cree una UILabel y colóquela en su vista de texto (asigne el texto como gris de color de marcador de posición; puede hacer todo esto en su xib) Ahora en su archivo de encabezado declare la UILabel y también la vista de texto Abandonar ahora simplemente puede ocultar la etiqueta Al hacer clic en la vista de texto.

código completo a continuación

encabezamiento

@interface ViewController :UIViewController<UITextViewDelegate>{ } @property (nonatomic,strong) IBOutlet UILabel *PlceHolder_label; @property (nonatomic,strong) IBOutlet UITextView *TextView; @end

implementación

@implementation UploadFoodImageViewController @synthesize PlceHolder_label,TextView; - (void)viewDidLoad { [super viewDidLoad]; } - (BOOL)textViewShouldBeginEditing:(UITextView *)textView{ if([textView isEqual:TextView]){ [PlceHolder_label setHidden:YES]; [self.tabScrlVw setContentOffset:CGPointMake(0,150) animated:YES]; } return YES; }

@fin

No olvide conectar el textView y UILabel al propietario de archivos desde xib


Aquí hay otra manera de hacerlo, una que reproduce la pequeña muesca del UITextFieldmarcador de posición:

Arrastre un UITextFieldderecho debajo de UITextViewpara que sus esquinas superiores izquierdas estén alineadas. Agregue el texto de su marcador de posición al campo de texto.

En viewDidLoad, agregue:

[tView setDelegate:self]; tView.contentInset = UIEdgeInsetsMake(-8,-8,0,0); tView.backgroundColor = [UIColor clearColor];

Luego añade:

- (void)textViewDidChange:(UITextView *)textView { if (textView.text.length == 0) { textView.backgroundColor = [UIColor clearColor]; } else { textView.backgroundColor = [UIColor whiteColor]; } }


Eche un vistazo a UTPlaceholderTextView .

Esta es una subclase conveniente de UITextView que admite marcadores de posición similares a los de UITextField. Principales peculiaridades:

  • No usa subvistas
  • No anula drawRect:
  • El marcador de posición podría ser de una longitud arbitraria y representarse de la misma manera que el texto habitual

Hice mi propia versión de la subclase de ''UITextView''. Me gustó la idea de Sam Soffes de usar las notificaciones, pero no me gustó el drawRect: sobrescribir. Me parece una exageración. Creo que hice una implementación muy limpia.

Puedes ver mi subclase here . También se incluye un proyecto de demostración.


Leí todo esto, pero se me ocurrió una solución muy corta, Swift 3, que ha funcionado en todas mis pruebas. Podría soportar un poco más de generalidad, pero el proceso es simple. Aquí está todo lo que llamo "TextViewWithPlaceholder".

import UIKit class TextViewWithPlaceholder: UITextView { public var placeholder: String? public var placeholderColor = UIColor.lightGray private var placeholderLabel: UILabel? // Set up notification listener when created from a XIB or storyboard. // You can also set up init() functions if you plan on creating // these programmatically. override func awakeFromNib() { super.awakeFromNib() NotificationCenter.default.addObserver(self, selector: #selector(TextViewWithPlaceholder.textDidChangeHandler(notification:)), name: .UITextViewTextDidChange, object: self) placeholderLabel = UILabel() placeholderLabel?.alpha = 0.85 placeholderLabel?.textColor = placeholderColor } // By using layoutSubviews, you can size and position the placeholder // more accurately. I chose to hard-code the size of the placeholder // but you can combine this with other techniques shown in previous replies. override func layoutSubviews() { super.layoutSubviews() placeholderLabel?.textColor = placeholderColor placeholderLabel?.text = placeholder placeholderLabel?.frame = CGRect(x: 6, y: 4, width: self.bounds.size.width-16, height: 24) if text.isEmpty { addSubview(placeholderLabel!) bringSubview(toFront: placeholderLabel!) } else { placeholderLabel?.removeFromSuperview() } } // Whenever the text changes, just trigger a new layout pass. func textDidChangeHandler(notification: Notification) { layoutSubviews() } }


- (void)textViewDidChange:(UITextView *)textView { placeholderLabel.hidden = YES; }

Pon una etiqueta sobre la vista de texto.