Mi aplicación usa una UITextView. Ahora quiero el UITextView tener un marcador de posición similar a la que se pueden establecer para un UITextField.

Cómo hacerlo?

  • Three20 del TTTextEditor (sí misma mediante UITextField) apoya el texto del marcador de posición, así como el crecimiento de la estatura (que se convierte en un UITextView).
  • Aquí la pequeña e impresionante solución para este
  • Cómo sobre el uso de UITextView+Marcador de posición categoría? github.com/devxoul/UITextView-Placeholder
  • Estoy a favor de @devxoul la solución de coz usos de la categoría, no la subclase. Y también crea un campo de ‘marcador’ opciones (texto de marcador de posición & color del texto) en IB del inspector. Utiliza algunas técnicas de unión. Lo que es un gran código
  • Si usted está usando UITextView la solución se vuelve muy diferente. Aquí hay un par de soluciones. Flotante Marcador de posición y Falsos Nativo de Marcadores de posición
  • Pruebe esta respuesta 🙂 [_textView setTextColor:[UIColor lightGrayColor]];
  • Lo interesante es que el nativo de iOS app de Calendario tiene varias líneas de texto editable – con un marcador de posición (la adición de ‘Notas’ para un evento). Así que hay evidencia directa de que Apple sí mismos reconocen la necesidad/uso para él.

60 Comentarios

  1. 669

    Hice un par de modificaciones menores a la bcd solución para permitir la inicialización de un Xib archivo, ajuste de texto, y para mantener el color de fondo. Espero que salvar a los demás de los problemas.

    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
    • Cada vez que drawRect se llama una nueva UILabel se agrega a la vista de la jerarquía. No he hecho un montón de alrededor de drawRect — es la suposición de que no hay persistencia en la vista heararchy, de manera que cada vez drawRect se llama el agregado previamente etiqueta subvista ha sido puesto en libertad?
    • En general es una buena aplicación, pero estoy de acuerdo con Sam Soffes la respuesta-la adición de una etiqueta a la vista de jerarquía es muy pesado para lo que es necesario. Además de su aplicación de _updateShouldDrawPlaceholder y el uso de setNeedsDisplay es más completo.
    • en algunos casos (esp. iOS 5 compatibilidad) es necesario reemplazar pegar: – (void)pasta:(id)sender { [super pegar:remitente]; [self textChanged:nil]; }
    • Cosas buenas! Recordatorio sobre las mejores prácticas para NSString (o de cualquier clase que tiene un NSMutableXXX equivalente), la propiedad debe ser «copia» y no de «retener».
    • No podía el código duplicado en initWithFrame: y awakeFromNib: poner en un solo método (para facilitar cualquier diseño adicionales que podría hacerlo)? O ¿el que tiene más consecuencias?
    • Supongo que sí (que acaba de tomar el código original de Jason George ;)) – pero realmente no sobra nada. Creo que el código es bastante fácil de leer de la manera que es.
    • ¿Cómo se puede crear una instancia de este código? No veo ningún marcador de posición de texto y nada se borra cuando empiezo a escribir.
    • usted necesita cambiar la línea de interruptor [placeHolderLabel setLineBreakMode:NSLineBreakByWordWrapping]; en IOs6
    • Sería mejor comprobar placeholder == nil antes del establecimiento de la @»». En el interface builder usted puede utilizar el Definido por el Usuario en tiempo de ejecución Atributos para establecer el marcador de posición (y placeholderColor) y que en la actualidad recibe reemplazado por el awakeFromNib método. He cambiado la mía.
    • Trate de usar: ((UIPlaceHolderTextView *)MyTextView.placeholder).placeholder = @"blabla";
    • jeremy respuesta me dio sigAbort , así que traté de instancia de UIPlaceHolderTextView por ejemplo:- profleBio = [[UIPlaceHolderTextView alloc] init…y [profleBio setPlaceholder:@»Bla»];
    • Este es un muy, muy mal escrito implementación. Aquí está una manera mucho más limpio versión que también los relojes para el dictado de cambios: github.com/cbowns/MPTextView
    • Yo, sin embargo, usted puede agregar marcador de posición en IB.
    • No modifique el punto de vista de la jerarquía en drawRect.
    • Esta práctica puede conducir a algunos errores. Hasta donde yo sé, esto puede romper la animación en la backgroundColor propiedad de alguna manera. Supongo que es debido a modificar la vista de jerarquía en drawRect.
    • Alguien ha logrado sumar una versión de iOS8 uso de Swift?
    • Para lidiar no sólo con text pero también propiedades tales como font o textAlignment, usted puede tratar de esta categoría: github.com/devxoul/UITextView-Placeholder
    • El marcador no se actualizará cuando si se establece de nuevo el código. Reemplazar el setter para arreglar esto: - (void)setPlaceholder:(NSString *)placeholder { _placeholder = placeholder; [self setNeedsDisplay]; }
    • Usted puede utilizar otro UITextView en lugar de UILabel para que coincida con el texto insertos.
    • Por desgracia, @cbowns MPTextView repo ya no se mantiene.
    • Sugerencia: puede agregar IBDesignable a el .h propiedades (justo antes de la declaración de tipo) para poder establecer el texto del marcador de posición y de color en el Guión!
    • No entiendo por qué Apple no ha añadido una propiedad de marcador de posición para UITextView. No lo entiendo.
    • contiene demasiados errores lógicos. En mi caso necesito para hacer la etiqueta público, ya que el marco no trabajar correctamente. Necesito la instalación de las limitaciones – que no funciona por defecto también, porque de tonto etiqueta de inicialización (dentro de drawRect y no se crea si el marcador está vacío), y etc.

  2. 621

    Manera fácil, basta con crear texto de marcador de posición en UITextView mediante el siguiente UITextViewDelegate métodos:

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

    sólo recuerde para establecer 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 hacer que los padres de clase UITextViewDelegate antes de incluir estos métodos por ejemplo,

    @interface MyClass () <UITextViewDelegate>
    @end

    Código 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()
    }

    sólo recuerde para establecer 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 hacer que los padres de clase UITextViewDelegate antes de incluir estos métodos por ejemplo,

    class MyClass: UITextViewDelegate
    {
    }
    • Esto es genial (me encanta simple) para 1 pantalla con 1 UITextView. La razón para el más complicado de soluciones es que si usted tiene una mayor aplicación con MUCHAS pantallas y MUCHOS UITextViews, usted no quiere hacer esto una y otra. Usted probablemente desee subclase UITextView para que se ajuste a sus necesidades y, a continuación, utilizar ese.
    • Si alguien escribe «texto de marcador de posición aquí…» en el cuadro de texto también se comporta como marcador de posición de texto. También, durante la presentación, usted tendrá que comprobar para todos los criterios.
    • de acuerdo con @jklp, los de arriba-votaron más de la ingeniería de métodos no son tan bonitas como esta.
    • De esta forma se rompe enablesReturnKeyAutomatically. 🙁
    • El marcador de posición de texto se supone que aun cuando el campo se convierte en el destinatario, y este método no funciona para este.
    • Utilice [UIColor colorWithWhite:0.8 alfa:1.0] para el mismo color que UITextField color de marcador de posición en iOS 7.
    • Yo diría que la «sobre-ingeniería» manera más limpia y re-utilizable…y parece que no altere la text atributo de la textview que es un poco agradable..mientras que este método modifica
    • Esto va a exhibir un comportamiento extraño si el usuario pulsa en el texto de marcador de posición. En general, usted desea que el texto desaparezca si que ocurre, pero se supone que el usuario solo se puede escribir. No es un gran problema, pero un notable sutileza que me eligió Sam Soffes solución.
    • Pero que ignora el hecho de que continúa mostrando el texto de marcador de posición después de que el campo de enfoque de ganancias es un muy estúpido de la convención de que sólo se convirtió en lugar común, porque es lo que Apple eligió.
    • No me gusta este comportamiento, pero el OP dijo que quería un marcador de posición «similar a la que se pueden establecer para un UITextField». Que implica que quieren que sus marcador de posición para que se comporten como mucho como UITextField como sea posible.
    • por qué las llamadas a becomeFirstResponder y resignFirstResponder en los métodos de delegado?
    • Pensaba que esto era bueno – sin embargo no tiene la UX – es decir, texto de marcador de posición se mantiene al centro de atención inmediata y no entró en el texto, vuelve a aparecer cuando no hay texto introducido. Buen intento, aunque 🙂

  3. 119

    Yo no estaba muy feliz con cualquiera de las soluciones publicado como eran un poco pesados. La adición de puntos de vista a la vista no es ideal (especialmente en drawRect:). Ambos tenían fugas, lo que no 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 sencilla que la de los demás, ya que no uso subvistas (o pérdidas). Siéntase libre de utilizar.

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

    Actualización 11/24/13: seleccione nuevo repo.

    • Me gusta tu solución, y he añadido un reemplazo de setText a actualizar marcador de posición cuando el cambio de propiedad de texto mediante programación: – (void)setText:(NSString *)string { [super setText:string]; [self _updateShouldDrawPlaceholder]; }
    • Gracias! He añadido esto a mi clase: gasolina soff.me/2Jds
    • Me gusta tu solución también, pero has perdido la awakefromnib método para que su método init no siempre recibe llamadas. La tomé de uno de los otros aquí.
    • Oh buen llamada. Yo no uso IB, así que nunca se quedó en eso. Voy a echar un vistazo. Gracias.
    • Nota-la magia de los números varían dependiendo del tamaño de la fuente. El posicionamiento exacto puede ser calculada a partir de la fuente, pero probablemente no vale la pena para esta aplicación. La correcta posición del marcador de posición debe ser 2px a la derecha de la posición del cursor cuando no hay texto.
    • Para resolver la carga de punta: es probable que desee agregar un – (id) initWithCoder:(NSCoder *)aDecoder; inicializador para acompañar a la existente.
    • He actualizado mi respuesta para agregar IB apoyo.
    • Este es dulce. El notification argumento está mal escrito en el último método, sin embargo, y es demasiado pequeño un cambio a presentar como una edición.
    • He hecho una versión modificada para iOS7: stackoverflow.com/a/19519213/37346
    • Me gusta el enfoque. Me portado a Swift/iOS 8 y publicado a continuación. Algunos retoques pero a mí me funciona con una base de UITextView hasta ahora. Gracias
    • Esto no funciona en iOS 9.2, me gustaría ir con este github.com/gcamp/GCPlaceholderTextView (siguiente respuesta), funciona perfectamente y se puede establecer marcador de posición de texto de marcador de posición y el color del texto.

  4. 52

    Lo que puedes hacer es configurar la vista texto con algo de valor inicial en el text de la propiedad, y cambiar el textColor a [UIColor grayColor] o algo similar. Entonces, cada vez que la vista de texto se pueda editar, borrar el texto y presentar un cursor, y si el campo de texto está siempre vacía de nuevo, poner el texto de marcador de posición de la espalda. Cambiar el color a [UIColor blackColor] según corresponda.

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

    • Yo siempre he usado lightGrayColor, que parece coincidir con el color del texto de marcador de posición.
    • Estoy leyendo esto ahora, pero quiero agregar que al restaurar el color negro y el restablecimiento de la propiedad de texto en textViewShouldBeginEditing:(UITextView *)textView funciona muy bien. Esta es una muy buena y rápida solución en comparación con las soluciones de abajo (pero todavía soluciones elegantes a continuación, subclases uitextview. Mucho más modular).
    • Cierto, pero no imitar el comportamiento de UITextField, que sólo se reemplaza su texto de marcador de posición cuando el usuario escribe algo, no cuando la edición que comienza, y que añade el marcador de posición de nuevo el segundo la vista está vacío, no cuando la edición en realidad acabados.
  5. 50

    Me encontré una manera muy fácil de imitar a un lugar de titular

    1. en la PUNTA o el código establece su textView del textColor a lightGrayColor (la mayoría del tiempo)
    2. asegúrese de que su textView del delegado está vinculada a la del propietario del archivo y aplicar UITextViewDelegate en el archivo de encabezado
    3. configurar el texto predeterminado de la vista de texto (ejemplo: «Título del marcador de posición»)
    4. implementar: (BOOL) textViewShouldBeginEditing:(UITextView *)textView

    Edición:

    Cambiado instrucciones if para comparar las etiquetas en lugar de texto. Si el usuario elimina su texto era posible que accidentalmente borrar una parte de el en lugar del titular @"Foobar placeholder".Esto significaba que si el usuario vuelva a entrar en el textView el siguiente método de delegado, -(BOOL) textViewShouldBeginEditing:(UITextView *) textView, no iba a funcionar como se esperaba. Traté de comparar el color del texto en la declaración si, pero encontró que la luz gris de color establecido en el interface builder no es el mismo como la luz gris de color establecido 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 de marcador de posición cuando el teclado vuelve y la [textView longitud] == 0

    EDICIÓN:

    Sólo para hacer la última parte más clara – aquí es cómo se puede establecer el texto de marcador de posición de la espalda:

    - (void)textViewDidChange:(UITextView *)textView
    {
    if([textView.text length] == 0)
    {
    textView.text = @"Foobar placeholder";
    textView.textColor = [UIColor lightGrayColor];
    textView.tag = 0;
    }
    }
    • Me gusta este enfoque mucho! La única cosa que me gustaría hacer a la edición anterior sería para mover la aplicación de la textViewDidChange: el método y en la textViewDidEndEditing: método, de modo que el texto de marcador de posición sólo se devuelve una vez que haya terminado de trabajar con el objeto.
  6. 46

    Puede establecer la etiqueta de la UITextView por

    [UITextView addSubView:lblPlaceHoldaer];

    y ocultarla en TextViewdidChange método.

    Esta es la simple & de manera fácil.

  7. 45

    Si alguien tiene una Solución para Swift:

    Agregar 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
    }
    }
    • esto está bien, pero no lo suficientemente bueno. si el usuario tipo «Texto de Marcador de posición…» (caso extremo obviamente), en el que se rompe la lógica de su
  8. 44

    Simple Swift 3 solución

    Agregar UITextViewDelegate a su clase

    Conjunto yourTextView.delegate = self

    Crear placeholderLabel y posición dentro de yourTextView

    Ahora se acaba de animar 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
    }
    }
    }

    usted podría tener que jugar con placeholderLabel posición para el sistema, pero que no debería ser demasiado difícil

    • Gran respuesta, solución simple. He añadido una pequeña mejora para animar sólo cuando el alfa deben cambiar: let alpha = CGFloat(textView.text.isEmpty ? 1.0 : 0.0) if alpha != lblPlaceholder.alpha { UIView.animate(withDuration: 0.3) { self.lblPlaceholder.alpha = alpha } }
    • su pequeña mejora realmente funcionó para mí
    • Esto funcionó muy bien! Gracias
  9. 24

    Me extendida KmKndy la respuesta, por lo que el marcador de posición permanece visible hasta que el usuario inicia la edición de la UITextView en lugar de simplemente pulsa en ella. Esto se refleja en la funcionalidad en el Twitter y Facebook apps. Mi solución no requiere la subclase y funciona si el usuario escribe directamente o pega el texto!

    Marcador de posición en UITextView

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

    sólo recuerde para establecer 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 hacer que los padres de clase UITextView delegado antes de incluir estos métodos por ejemplo,

    @interface MyClass () <UITextViewDelegate>
    @end
    • Solución agradable!!!
  10. 20

    Recomiendo el uso de SZTextView.

    https://github.com/glaszig/SZTextView

    Agregar su defecto UITextView de storyboard y, a continuación, cambiar su clase personalizada para SZTextView como el de abajo, 👇 👇 👇 👇

    Marcador de posición en UITextView

    Verá dos nueva opción en el Attribute Inspector 👇👇👇👇

    Marcador de posición en UITextView

  11. 18

    A continuación es un Swift puerto de «SAMTextView» ObjC código publicado como uno de los primeros puñado de respuestas a la pregunta. He probado en iOS 8. Jugué un par de cosas, incluyendo los límites de desplazamiento para la colocación del marcador de posición de texto, como el original era demasiado alto y demasiado lejos a la derecha de (utilizados sugerencia en uno de los comentarios a ese post).

    Sé que hay un montón de soluciones simples, pero me gusta el enfoque de creación de subclases UITextView porque es reutilizable y no tengo para el desorden de clases de la utilización de 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)
    }
    }
    • thks para hacer el swift versión, puede explicar cuál es el punto de tener un awakeFromNib método que acaba de llamar a super?
    • Se establece el marcador de posición, pero no se actualiza una vez que usted comience a escribir.
    • No importa, me puso la llamada de notificación en awakeFromNib y funciona ahora.
    • cualquier swift 2 versión ?
  12. 12

    esta es la forma en que 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
  13. 12

    Aquí está una manera fácil solución que se comporta exactamente igual que UITextField del marcador de posición, pero no requiere de dibujo de vistas personalizadas, o dimitir de primera respuesta.

    - (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 otro si la declaración es para el caso de que no se introduce nada y el usuario presiona la tecla de retroceso)

    Acaba de establecer su clase como un UITextViewDelegate. En viewDidLoad se deben 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;
    }
    • La cosa es que si el usuario toca en algún lugar en el medio de «texto de marcador de posición» símbolo de intercalación se queda allí.
  14. 10

    Lo siento para agregar otra pregunta, Pero me acaba de sacar algo como esto y esto creó el más cercano a UITextField tipo de marcador de posición.

    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);
    }
    }
    • He tenido que cambiar el orden de los comandos en la primera instrucción if if(textView.textColor == [UIColor lightGrayColor]){ textView.textColor = [UIColor blackColor]; textView.text = [textView.text substringToIndex: 1]; de lo Contrario, el primer carácter que se introducen en el textview se coloca al final del texto
    • Se está trabajando para mí en cambio substringToIndex 0
  15. 9

    Hola que usted puede utilizar IQTextView disponible en IQKeyboard Manager es simple de usar y de integrar acaba de establecer la clase de su textview para IQTextView y usted puede utilizar su propiedad para la configuración de marcador de posición de la etiqueta con el color que desee.
    Puede descargar la biblioteca de IQKeyboardManager

    o se puede instalar desde cocoapods.

    • IQKeyboardManager es muy útil y sin codificación. La mejor respuesta para mí!
    • En realidad, yo upvote y dejar un comentario para la razón. No sé IQTextView está disponible en IQKeyboardManager antes.
    • He tenido un problema con el delegado. Me quité de la clase, el delegado de anular y el UITextViewDelegate funcionado bien
  16. 7

    Manera sencilla de usar esta dentro de alguna línea de código:

    Tomar una etiqueta hasta UITextView en .nib
    la conexión de esta etiqueta con su código ,
    Después de ella.

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

    He modificado Sam Soffes aplicación para trabajar 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 = nil en los métodos que podrían cambiar la fuente y otras cosas que que les pudieran afectar. También puede ser que desee para saltar «perezoso» hacer de los atributos diccionario si no es el error.

    EDICIÓN:

    Recuerde llamar a setNeedsDisplay en una versión sustituida de setBounds si te gusta el marcador de posición con buen aspecto después de autodiseño de animaciones y similares.

    • Creo que se debe agregar inserciones.a la izquierda, a la distancia x del parámetro.
    • no es setFrame en lugar de setBounds?
    • Nope! setFrame no es llamado durante el diseño de animaciones que parece.
  18. 6

    También podría crear una nueva clase TextViewWithPlaceholder como una subclase de UITextView.

    (Este código es un poco duras, pero yo creo que es en la pista de la derecha.)

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

    De su delegado, añadir esto:

    - (void)textViewDidChange:(UITextView *)textView
    {
    if ([textView respondsToSelector: @selector(updateForTextChange)])
    {
    [textView updateForTextChange];
    }
    }
    • Para obtener el comportamiento exacto que usted debe pintar su propio marcador de posición reemplazando drawRect: (dibujar marcador de posición sólo si!!![auto isFirstResponder] && [[self texto] longitud] == 0), y llamar a setNeedsDisplay dentro de becomeFirstResponder y resignFirstResponder
  19. 6

    Hice mi propia versión de la subclase de ‘UITextView’. Me gustó Sam Soffesque la idea de utilizar las notificaciones, pero no me gustó el drawRect: sobrescribir. Parece demasiado para mí. Creo que hice un muy limpio implementación.

    Usted puede mirar en mi subclase aquí. Un proyecto de demostración también se incluye.

  20. 6

    Este hilo ha tenido un montón de respuestas, pero aquí la versión que yo prefiero.

    Se se extiende la existente UITextView clase, de modo que es fácilmente reutilizable, y no interceptar los eventos como textViewDidChange (que podría romper código de usuario, si ya estaban interceptando estos eventos en otros lugares).

    Usando mi código (que se muestra a continuación), usted puede fácilmente agregar un marcador de posición para cualquiera de sus UITextViews como este:

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

    Cuando se establece este nuevo valor del marcador de posición, tranquilamente añade un UILabel en la parte superior de su UITextView, a continuación, ocultar/muestra como necesario:

    Marcador de posición en UITextView

    Bien, para realizar estos cambios, agregar un «UITextViewHelper.h» el archivo que contiene 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 UITextViewHelper.m archivo que contiene esta:

    // 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 usted ha agregado a su proyecto, y que incluía el .h archivo…

    #import "UITextViewHelper.h"

    …usted puede fácilmente hacer uso de los marcadores de posición en UITextViews.

    Hay una gotcha sin embargo.

    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 de el texto. Cuando se establece la text valor, ninguno de los regulares de notificaciones se llama, así que no podía encontrar la manera de llamar a mi función para decidir si mostrar/ocultar el marcador de posición.

    La solución es establecer la textValue en lugar de text:

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

    Alternativamente, usted puede configurar el text valor, a continuación, llamar checkIfNeedToDisplayPlaceholder.

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

    Me gusta soluciones como esta, ya que «llenar el hueco» entre lo que Apple nos ofrece, y lo que para nosotros (como desarrolladores) realmente necesita en nuestras aplicaciones. Escribe este código una vez, agregar a la biblioteca de «ayudante» .m/.h archivos, y, con el tiempo, el SDK de realidad comienza a volverse menos frustrante.

    (Escribí una similar ayudante para añadir un botón «borrar» para mi UITextViews, otra cosa que molesto que existe en UITextField pero no en UITextView…)

    • Me gusta lo limpio que es esto, pero no me gusta cómo se requiere un segundo UIView/UILabel (y realmente no se heredan los atributos/colores/font fácilmente desde el UITextView). Buen aporte aunque
  21. 6

    Primero tener una etiqueta en .h archivo.

    Aquí me tomo

    UILabel * lbl;

    A continuación, en .m por debajo de la viewDidLoad declarar

    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 declarar

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

    Y su Textview marcador de posición está listo !

    • Keep it simple, no se puede pedir más! de lujo libs no son necesarias.
  22. 6

    Recomiendo usar pod «UITextView+Marcador de posición’

    pod 'UITextView+Placeholder'

    sobre el código

    #import "UITextView+Placeholder.h"
    ////   
    UITextView *textView = [[UITextView alloc] init];
    textView.placeholder = @"How are you?";
    textView.placeholderColor = [UIColor lightGrayColor];
  23. 5
        - (void)textViewDidChange:(UITextView *)textView
    {
    placeholderLabel.hidden = YES;
    }

    poner una etiqueta sobre el textview.

    • O mejor aún, se puede volver a mostrar cuando no está presente el texto: lblPlaceholder.hidden = ![textView.texto isEqualToString:@»»];
  24. 5

    No es posible crear marcador de posición en UITextView pero usted puede generar efecto como titular por esto.

      - (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 usted puede agregar la etiqueta en el textview como

           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;
    }  
    }
  25. 5

    Esto imita UITextField del marcador de posición a la perfección, donde el marcador de posición de texto se mantiene hasta que escriba 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
    }
    }
    }
  26. 4

    He aquí otra manera de hacerlo, que reproduce el leve hendidura de UITextField‘s de marcador de posición:

    Arrastre un UITextField derecho en virtud de la UITextView de modo que su parte superior izquierda esquinas estén alineadas. Añada su texto de marcador de posición para el campo de texto.

    En viewDidLoad, agregar:

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

    A continuación, añadir:

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

    Permite hacer fácil

    Crear un UILabel y el lugar en su vista de texto(el texto de Marcador de posición de conjunto de color gris-usted puede hacer todo esto en su xib)
    Ahora en que el archivo de encabezado de declarar la UILabel y también el de la textviewDelegate
    Ahora simplemente puede ocultar la etiqueta cuando usted haga clic en el textview

    completa el siguiente código de

    encabezado

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

    aplicació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;
    }

    @finales

    No olvide conectar el textView y UILabel a filesowner de xib

  28. 4

    Echa un vistazo a UTPlaceholderTextView.

    Esta es una conveniente subclase de UITextView que soporta el marcador de posición similar a la de UITextField. Principales particularidades:

    • No uso subvistas
    • No anula drawRect:
    • Marcador de posición podría ser de longitud arbitraria, y se representan de la misma manera como de costumbre texto
  29. 4

    He leído a través de todos estos, sino que vino para arriba con una muy corto, Swift 3, la solución que ha trabajado en todas mis pruebas. Podría estar un poco más generalidad, pero el proceso es simple. Aquí está toda la cosa de la que yo 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()
    }
    }
    • Algunas de las preocupaciones aquí. No debe llamar a layoutSubviews() directamente. Y no quitar el NotificationCenter observador.
  30. 4

    He escrito una clase en swift. Usted puede importar esta clase cuando sea necesario.

    import UIKit

    clase pública CustomTextView: UITextView {

    private struct Constants {
    static let defaultiOSPlaceholderColor = UIColor(red: 0.0, green: 0.0, blue: 0.0980392, alpha: 0.22)
    }
    private let placeholderLabel: UILabel = UILabel()
    private var placeholderLabelConstraints = [NSLayoutConstraint]()
    @IBInspectable public var placeholder: String = "" {
    didSet {
    placeholderLabel.text = placeholder
    }
    }
    @IBInspectable public var placeholderColor: UIColor = CustomTextView.Constants.defaultiOSPlaceholderColor {
    didSet {
    placeholderLabel.textColor = placeholderColor
    }
    }
    override public var font: UIFont! {
    didSet {
    placeholderLabel.font = font
    }
    }
    override public var textAlignment: NSTextAlignment {
    didSet {
    placeholderLabel.textAlignment = textAlignment
    }
    }
    override public var text: String! {
    didSet {
    textDidChange()
    }
    }
    override public var attributedText: NSAttributedString! {
    didSet {
    textDidChange()
    }
    }
    override public var textContainerInset: UIEdgeInsets {
    didSet {
    updateConstraintsForPlaceholderLabel()
    }
    }
    override public init(frame: CGRect, textContainer: NSTextContainer?) {
    super.init(frame: frame, textContainer: textContainer)
    commonInit()
    }
    required public init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    commonInit()
    }
    private func commonInit() {
    NSNotificationCenter.defaultCenter().addObserver(self,
    selector: #selector(textDidChange),
    name: UITextViewTextDidChangeNotification,
    object: nil)
    placeholderLabel.font = font
    placeholderLabel.textColor = placeholderColor
    placeholderLabel.textAlignment = textAlignment
    placeholderLabel.text = placeholder
    placeholderLabel.numberOfLines = 0
    placeholderLabel.backgroundColor = UIColor.clearColor()
    placeholderLabel.translatesAutoresizingMaskIntoConstraints = false
    addSubview(placeholderLabel)
    updateConstraintsForPlaceholderLabel()
    }
    private func updateConstraintsForPlaceholderLabel() {
    var newConstraints = NSLayoutConstraint.constraintsWithVisualFormat("H:|-(\(textContainerInset.left + textContainer.lineFragmentPadding))-[placeholder]",
    options: [],
    metrics: nil,
    views: ["placeholder": placeholderLabel])
    newConstraints += NSLayoutConstraint.constraintsWithVisualFormat("V:|-(\(textContainerInset.top))-[placeholder]",
    options: [],
    metrics: nil,
    views: ["placeholder": placeholderLabel])
    newConstraints.append(NSLayoutConstraint(
    item: placeholderLabel,
    attribute: .Width,
    relatedBy: .Equal,
    toItem: self,
    attribute: .Width,
    multiplier: 1.0,
    constant: -(textContainerInset.left + textContainerInset.right + textContainer.lineFragmentPadding * 2.0)
    ))
    removeConstraints(placeholderLabelConstraints)
    addConstraints(newConstraints)
    placeholderLabelConstraints = newConstraints
    }
    @objc private func textDidChange() {
    placeholderLabel.hidden = !text.isEmpty
    }
    public override func layoutSubviews() {
    super.layoutSubviews()
    placeholderLabel.preferredMaxLayoutWidth = textContainer.size.width - textContainer.lineFragmentPadding * 2.0
    }
    deinit {
    NSNotificationCenter.defaultCenter().removeObserver(self,
    name: UITextViewTextDidChangeNotification,
    object: nil)
    }

    }

    Marcador de posición en UITextView

    • Gracias! Solución agradable
    • Este es en realidad uno de los más limpios soluciones que yo era capaz de encontrar y terminé con esto.. sobre todo teniendo inserciones en consideración y uso de restricciones para la etiqueta es un buen toque, no he visto muchas (alguna?) otras soluciones teniendo cuidado de cambiar los límites, fuentes, RTL, etc.
  31. 3

    ACEPTAR mi ansewer es un poco diferente
    Puedo crear una pequeña clase para hacerlo para usted.

    TextViewShader.m archivo

    #import "TextViewShader.h"
    @implementation TextViewShader
    -(id)initWithShadedTextView:(NSString *)text textViewToShade:(UITextView *)textview {
    self = [super initWithFrame:textview.frame];
    if (self) {
    if (shadeLabel==nil)
    {
    shadeLabel= [[UILabel alloc]initWithFrame:CGRectMake(10, 0, textview.frame.size.width, 30)];
    }
    shadeLabel.text =text;//@"Enter Your Support Request";
    shadeLabel.textColor = [UIColor lightGrayColor];
    [textview setDelegate: self];
    [textview addSubview:shadeLabel];
    }
    return self;
    }
    -(void)textViewDidChange:(UITextView *)textView{
    if (textView.text.length==0)
    {
    shadeLabel.hidden=false; 
    }
    else
    {
    shadeLabel.hidden=true;
    }
    }
    @end

    TextViewShader.h archivo

    #import <UIKit/UIKit.h>
    @interface TextViewShader : UIView<UITextViewDelegate>{
    UILabel *shadeLabel;
    }
    -(id)initWithShadedTextView:(NSString *)text textViewToShade:(UITextView *)textview ;
    @end

    esta es la simple línea de código de uso (no te olvides de añadir #import «TextViewShader.h»)

     TextViewShader* shader = [[TextViewShader alloc]initWithShadedTextView:@"Enter Your Support Request" textViewToShade: youruitextviewToshade];

    divertirse 🙂

  32. 3

    He creado una variable de instancia para comprobar si te voy a mostrar el marcador de posición o no:

    BOOL showPlaceHolder;
    UITextView * textView; //and also the textView

    Sobre viewDidLoad me puse:

    [self setPlaceHolder]; 

    Esto es lo que hace:

    - (void)setPlaceholder
    {
    textView.text = NSLocalizedString(@"Type your question here", @"placeholder");
    textView.textColor = [UIColor lightGrayColor];
    self.showPlaceHolder = YES; //we save the state so it won't disappear in case you want to re-edit it
    }

    También he creado un botón para renunciar al teclado. Usted no tiene que hacer esto, pero lo interesante aquí es que el marcador de posición se muestra de nuevo, si nada se ha introducido

    - (void)textViewDidBeginEditing:(UITextView *)txtView 
    {
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(resignKeyboard)];
    if (self.showPlaceHolder == YES) 
    {
    textView.textColor = [UIColor blackColor];
    textView.text = @"";
    self.showPlaceHolder = NO;
    }
    }
    - (void)resignKeyboard 
    {
    [textView resignFirstResponder];
    //here if you created a button like I did to resign the keyboard, you should hide it
    if (textView.text.length == 0) {
    [self setPlaceholder];
    }       
    }
  33. 3

    Sé que ya hay un montón de respuestas a este, pero realmente no encontrar ningún suficiente (al menos en Swift). Necesitaba el «marcador de posición» funcionalidad de la UITextField en mi UITextView (yo quería que el comportamiento exacto, incluyendo el texto de los atributos de la pantalla, animaciones, etc, y no quiero tener que mantener esto en el tiempo). Yo también quería una solución que proporciona el mismo borde exacto como un UITextField (no es un aproximado que se ve como se ve ahora, pero uno que se ve exactamente como es y siempre tendrá un aspecto exactamente igual). Así que mientras yo no era inicialmente un fan de la interferencia de un control adicional en la mezcla, parecía que en el fin de cumplir con mis metas que me tenía que usar un UITextField y deja que haga el trabajo.

    Esta solución maneja el posicionamiento del marcador de posición y mantener la fuente en la sincronización entre los dos controles para que el texto de marcador de posición es exactamente la fuente y la posición como el texto introducido en el control (algo que muchos de las otras soluciones no dirección).

    //This class is necessary to support "inset" (required to position placeholder 
    //appropriately in TextView)
    //
    class TextField: UITextField
    {
    var inset: UIEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0);
    override func textRectForBounds(bounds: CGRect) -> CGRect
    {
    return UIEdgeInsetsInsetRect(bounds, inset);
    }
    override func placeholderRectForBounds(bounds: CGRect) -> CGRect
    {
    return UIEdgeInsetsInsetRect(bounds, inset);
    }
    }
    //This class implements a UITextView that has a UITextField behind it, where the 
    //UITextField provides the border and the placeholder text functionality (so that the
    //TextView looks and works like a UITextField).
    //
    class TextView : UITextView, UITextViewDelegate
    {
    var textField = TextField();
    required init?(coder: NSCoder)
    {
    super.init(coder: coder);
    }
    override init(frame: CGRect, textContainer: NSTextContainer?)
    {
    super.init(frame: frame, textContainer: textContainer);
    self.delegate = self;
    //Create a background TextField with clear (invisible) text and disabled
    self.textField.borderStyle = UITextBorderStyle.RoundedRect;
    self.textField.textColor = UIColor.clearColor();
    self.textField.userInteractionEnabled = false;
    //Align the background TextView to where text appears in the TextField, so
    //that any placeholder will be in the correct position.
    self.textField.contentVerticalAlignment = UIControlContentVerticalAlignment.Top;
    self.textField.inset = UIEdgeInsets(
    top: self.textContainerInset.top,
    left: self.textContainerInset.left + self.textContainer.lineFragmentPadding,
    bottom: self.textContainerInset.bottom,
    right: self.textContainerInset.right
    );
    //The background TextField should use the same font (for the placeholder)
    self.textField.font = self.font;
    self.addSubview(textField);
    self.sendSubviewToBack(textField);
    }
    convenience init()
    {
    self.init(frame: CGRectZero, textContainer: nil)
    }
    override var font: UIFont?
    {
    didSet
    {
    //Keep the font of the TextView and background textField in sync
    self.textField.font = self.font;
    }
    }
    var placeholder: String? = nil
    {
    didSet
    {
    self.textField.placeholder = self.placeholder;
    }
    }
    override func layoutSubviews()
    {
    super.layoutSubviews()
    //Do not scroll the background textView
    self.textField.frame = CGRectMake(0, self.contentOffset.y, self.frame.width, self.frame.height);
    }
    //UITextViewDelegate - Note: If you replace delegate, your delegate must call this
    func scrollViewDidScroll(scrollView: UIScrollView)
    {
    //Do not scroll the background textView
    self.textField.frame = CGRectMake(0, self.contentOffset.y, self.frame.width, self.frame.height);
    }
    //UITextViewDelegate - Note: If you replace delegate, your delegate must call this
    func textViewDidChange(textView: UITextView)
    {
    //Updating the text in the background textView will cause the placeholder to 
    //appear/disappear (including any animations of that behavior - since the
    //textView is doing this itself).
    self.textField.text = self.text;
    }
    }
    • El código se bloquea. Considere la posibilidad de quitar fatalError
    • Me fijo (déjame saber si funciona). Lo que solía ser un dolor de cabeza para hacer el inicializador de trabajo, así que yo no apoyo Storyboard/XIB de inicialización (no utilizamos en nuestra aplicación podemos crear todos los controles mediante programación). Hago excepción «se bloquea». La intención de la fatalError fue para indicar que no admite la inicialización de Guión gráfico/XIB (a pesar de que era la verdad no es muy claro el mensaje).
  34. 3

    He creado un swift 3 versión de el ranking más alto de respuesta

    Sólo tienes que hacer subclases de UITextView.

    import UIKit
    class UIPlaceHolderTextView: UITextView {
    //MARK: - Properties
    @IBInspectable var placeholder: String?
    @IBInspectable var placeholderColor: UIColor?
    var placeholderLabel: UILabel?
    //MARK: - Initializers
    override func awakeFromNib() {
    super.awakeFromNib()
    }
    required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    //Use Interface Builder User Defined Runtime Attributes to set
    //placeholder and placeholderColor in Interface Builder.
    if self.placeholder == nil {
    self.placeholder = ""
    }
    if self.placeholderColor == nil {
    self.placeholderColor = UIColor.black
    }
    NotificationCenter.default.addObserver(self, selector: #selector(textChanged(_:)), name: NSNotification.Name.UITextViewTextDidChange, object: nil)
    }
    func textChanged(_ notification: Notification) -> Void {
    if self.placeholder?.count == 0 {
    return
    }
    UIView.animate(withDuration: 0.25) {
    if self.text.count == 0 {
    self.viewWithTag(999)?.alpha = 1
    }
    else {
    self.viewWithTag(999)?.alpha = 0
    }
    }
    }
    //Only override draw() if you perform custom drawing.
    //An empty implementation adversely affects performance during animation.
    override func draw(_ rect: CGRect) {
    super.draw(rect)
    if (self.placeholder?.count ?? 0) > 0 {
    if placeholderLabel == nil {
    placeholderLabel = UILabel.init()
    placeholderLabel?.lineBreakMode = .byWordWrapping
    placeholderLabel?.numberOfLines = 0
    placeholderLabel?.font = self.font
    placeholderLabel?.backgroundColor = self.backgroundColor
    placeholderLabel?.textColor = self.placeholderColor
    placeholderLabel?.alpha = 0
    placeholderLabel?.tag = 999
    self.addSubview(placeholderLabel!)
    placeholderLabel?.translatesAutoresizingMaskIntoConstraints = false
    placeholderLabel?.topAnchor.constraint(equalTo: self.topAnchor, constant: 7).isActive = true
    placeholderLabel?.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 4).isActive = true
    placeholderLabel?.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
    placeholderLabel?.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
    }
    placeholderLabel?.text = self.placeholder
    placeholderLabel?.sizeToFit()
    self.sendSubview(toBack: self.placeholderLabel!)
    }
    if self.text.count == 0 && (self.placeholder?.count ?? 0) > 0 {
    self.viewWithTag(999)?.alpha = 1
    }
    }
    }
    • Se está trabajando en Swift 4.
    • El marcador no se muestra en absoluto. Mediante El Uso De Swift 5. Alguna idea?
  35. 2
    - (BOOL) textViewShouldBeginEditing:(UITextView *)textView
    {
    //NSLog(@"textViewShouldBeginEditing");
    if( [tvComment.text isEqualToString:@"Comment"] && [tvComment.textColor isEqual:[UIColor lightGrayColor]] ){
    tvComment.text = @"";
    tvComment.textColor = [UIColor blackColor];
    }
    return YES;
    }
    - (void)keyboardWillBeHidden:(NSNotification*)aNotification{
    //NSLog(@"keyboardWillBeHidden");
    //Manage comment field placeholdertext
    if(tvComment.text.length == 0){
    tvComment.textColor = [UIColor lightGrayColor];
    tvComment.text = @"Comment";
    }
    }
    - (void)viewDidLoad
    {
    [super viewDidLoad];
    tvComment.textColor = [UIColor lightGrayColor];
    }

    TVComment es la propiedad que contiene el textView en cuestión. Esto va a hacer el truco.

  36. 2

    He escrito un limpiador de aplicación después de probar algunos de los enfoques propuestos y publicado en Github. Tire de las solicitudes y los temas son bienvenidos.

    Algunas mejoras clave que frente a otros enfoques que aquí se presenta:

    • No le asigna un UILabel dentro de drawRect:. (Por favor, no vuelvas a hacer eso.)
    • No se puede comparar el texto de la vista del texto actual a una deseada marcador de posición para intercambiar los colores.
    • Esconde el marcador de posición, mientras que el dictado es activo (como UITextField).
  37. 2

    He aquí una sencilla y de forma inteligente para conseguir el perfecto comportamiento.

    Vamos a pedir prestado el marcador de posición de UITextField.

    Marcador de posición en UITextView

    1. Configurar un campo de texto y establezca su texto transparente.

      self.placeholderTextField = [[UITextField alloc] init];
      /* adjust the frame to fit it in the first line of your textView */
      self.placeholderTextField.frame = CGRectMake(0.0, 0.0, yourTextView.width, 30.0);
      self.placeholderTextField.textColor = [UIColor clearColor];
      self.placeholderTextField.userInteractionEnabled = NO;
      self.placeholderTextField.font = yourTextView.font;
      self.placeholderTextField.placeholder = @"sample placeholder";
      [yourTextView addSubview:self.placeholderTextField];
    2. Conjunto textView del delegado y sincronizar el textField y textView.

      yourTextView.delegate = self;

      luego

      - (void)textViewDidChange:(UITextView *)textView {
      self.placeholderTextField.text = textView.text;
      }
    3. Eso es todo.
  38. 2
    - (void)viewDidLoad {
    [super viewDidLoad];
    self.textViewEmpty = YES;
    //Text view
    self.textView = [[UITextView alloc] init];
    self.textView.translatesAutoresizingMaskIntoConstraints = NO; //For AutoLayout
    self.textView.delegate = self;
    self.textView.textColor = [UIColor grayColor];
    self.textView.text = @"Placeholder";
    //Add subview and constraints
    }
    #pragma mark - UITextView
    - (BOOL)textViewShouldBeginEditing:(UITextView *)textView {
    if (self.isTextViewEmpty) {
    textView.textColor = [UIColor blackColor];
    textView.text = @"";
    }
    return YES;
    }
    - (void)textViewDidChange:(UITextView *)textView {
    if (textView.text.length > 0) {
    self.textViewEmpty = NO;
    } else {
    self.textViewEmpty = YES;
    }
    }
    - (BOOL)textViewShouldEndEditing:(UITextView *)textView {
    if (self.isTextViewEmpty) {
    textView.textColor = [UIColor lightGrayColor];
    textView.text = placeholderText;
    }
    return YES;
    }
  39. 2

    Un enfoque más sencillo es crear un secundario UITextView, con los mismos atributos que el texto original, salvo por una diferente textColor, con las restricciones para asegurar que queden alineadas. Luego, cuando los caracteres se introducen en el texto principal de la vista, ocultar el clonado vista de texto, de lo contrario mostrar el clonado vista de texto con texto.

    Esto puede lograrse de varias maneras, pero relativamente limpio manera sería subclase UITextView y mantener todo esto dentro de la lógica de la subclase.

    Así, la subclase UITextView y permitir que se cree que el lugar de la titular de la vista perezosamente:

    Archivo de interfaz:

    @interface FOOTextView : UITextView <UITextViewDelegate>
    @property (nonatomic, copy) NSString *placeholderText;
    - (void)checkPlaceholder;
    @end

    Archivo de implementación:

    #import "FOOTextView.h"
    @interface FOOTextView ()
    @property (nonatomic, strong) UITextView *placeholderTextView;
    @end
    @implementation FOOTextView
    - (void)checkPlaceholder {
    //Hide the placeholder text view if we've got any text
    self.placeholderTextView.hidden = (self.text.length > 0 || self.attributedText.length > 0);
    }
    - (void)setPlaceholderText:(NSString *)placeholderText {
    _placeholderText = [placeholderText copy];
    //Setup the placeholder text view if we haven't already
    [self setupPlaceholderTextView];
    //Apply the placeholder text to the placeholder text view
    self.placeholderTextView.text = placeholderText;
    }
    - (void)setupPlaceholderTextView {
    if (!self.placeholderTextView) {
    //Setup the place holder text view, duplicating our visual setup
    self.placeholderTextView = [[UITextView alloc] initWithFrame:CGRectZero];
    self.placeholderTextView.translatesAutoresizingMaskIntoConstraints = NO;
    self.placeholderTextView.textColor = self.placeholderTextColor ? self.placeholderTextColor : [UIColor colorWithRed:199.f/255.f green:199.f/255.f blue:205.f/255.f alpha:1.f];
    self.placeholderTextView.userInteractionEnabled = NO;
    self.placeholderTextView.font = self.font;
    self.placeholderTextView.textAlignment = self.textAlignment;
    self.placeholderTextView.backgroundColor = self.backgroundColor;
    self.placeholderTextView.editable = NO;
    //Our background color must be clear for the placeholder text view to show through
    self.backgroundColor = [UIColor clearColor];
    //Insert the placeholder text view into our superview, below ourself so it shows through
    [self.superview insertSubview:self.placeholderTextView belowSubview:self];
    //Setup constraints to ensure the placeholder text view stays aligned with us
    NSLayoutConstraint *constraintCenterX = [NSLayoutConstraint constraintWithItem:self.placeholderTextView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1.f constant:0.f];
    NSLayoutConstraint *constraintCenterY = [NSLayoutConstraint constraintWithItem:self.placeholderTextView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.f constant:0.f];
    NSLayoutConstraint *constraintWidth = [NSLayoutConstraint constraintWithItem:self.placeholderTextView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1.f constant:0.f];
    NSLayoutConstraint *constraintHeight = [NSLayoutConstraint constraintWithItem:self.placeholderTextView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeHeight multiplier:1.f constant:0.f];
    NSArray *constraints = @[constraintCenterX, constraintCenterY, constraintWidth, constraintHeight];
    [self.superview addConstraints:constraints];
    }
    }
    - (void)setPlaceholderTextColor:(UIColor *)placeholderTextColor {
    _placeholderTextColor = placeholderTextColor;
    self.placeholderTextView.textColor = _placeholderTextColor;
    }
    - (void)setBackgroundColor:(UIColor *)backgroundColor {
    //We don't want a background color ourselves, instead we want our placeholder text view to have the desired background color
    [self.placeholderTextView setBackgroundColor:backgroundColor];
    }
    - (void)removeFromSuperview {
    //Ensure we also remove our placeholder text view
    [self.placeholderTextView removeFromSuperview];
    self.placeholderTextView = nil;
    [super removeFromSuperview];
    }
    #pragma mark - Text View Delegation 
    - (void)textViewDidChange:(UITextView *)textView {
    [self checkPlaceholder];
    }
    @end

    El uso de la clase anterior, si se establece una instancia de FOOTextView del delegado a sí mismo, todo se va a trabajar fuera de la caja:

    FOOTextView *myTextView = ...
    myTextView.placeholderText = @"What's on your mind?";
    myTextView.placeholderTextColor = [UIColor lightGrayColor];
    myTextView.delegate = myTextView;

    Si quieres otro objeto para tomar el cargo como delegado, a continuación, sólo tiene que llamar a la vista del texto de la checkPlaceholder método en el textViewDidChange: método de delegado, por ejemplo;

    FOOTextView *myTextView = ...
    myTextView.placeholderText = @"What's on your mind?";
    myTextView.placeholderTextColor = [UIColor lightGrayColor];
    myTextView.delegate = self;
    self.myTextView = myTextView;
    - (void)textViewDidChange:(UITextView *)textView {
    //Call the checkPlaceholder method to update the visuals
    [self.myTextView checkPlaceholder];
    }
  40. 2

    En .clase h

    @interface RateCommentViewController : UIViewController<UITextViewDelegate>{IBoutlet UITextview *commentTxtView;}

    En .clase m

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

    Simulando Nativo De Marcadores De Posición


    Una queja común es que el iOS no ofrece un nativo de la función de marcador de posición para textviews. El UITextView extensión por debajo de los intentos de la dirección de que la preocupación por ofrecer la comodidad que uno esperaría de una función nativa, que sólo requieren una línea de código para agregar un marcador de posición para un textview instancia.

    La desventaja de esta solución es, porque margarita cadenas delegado de llamadas, es vulnerable a la (improbable) cambios en el UITextViewDelegate protocolo en una actualización de iOS. Específicamente, si iOS añade nuevos métodos de protocolo y de implementar cualquiera de ellos en la delegada para una vista de texto con un marcador de posición, los métodos no ser llamados a menos que usted haya también actualizado la extensión para reenviar las llamadas.

    Alternativamente, el Marcador De Posición En Línea respuesta es una sólida como una roca y tan simple como puede ser.


    Ejemplos de uso:


       • Si la vista de texto ganando el marcador de posición no utilizar un UITextViewDelegate:

        /* Swift 3 */
    class NoteViewController : UIViewController {
    @IBOutlet weak var noteView: UITextView!
    override func viewDidLoad() {
    noteView.addPlaceholder("Enter some text...",  color: UIColor.lightGray)
    }
    }

                                                – O –

       • Si la vista de texto ganando el marcador de posición hace utilizar un UITextViewDelegate:

        /* Swift 3 */
    class NoteViewController : UIViewController, UITextViewDelegate {
    @IBOutlet weak var noteView: UITextView!
    override func viewDidLoad() {
    noteView.addPlaceholder("Phone #", color: UIColor.lightGray, delegate: self)
    }
    }

    Aplicación (UITextView extensión):


    /* Swift 3 */
    extension UITextView: UITextViewDelegate
    {
    func addPlaceholder(_ placeholderText : String, 
    color : UIColor? = UIColor.lightGray,
    delegate : UITextViewDelegate? = nil) {
    self.delegate = self             //Make receiving textview instance a delegate
    let placeholder = UITextView()   //Need delegate storage ULabel doesn't provide
    placeholder.isUserInteractionEnabled = false  //... so we *simulate* UILabel
    self.addSubview(placeholder)     //Add to text view instance's view tree               
    placeholder.sizeToFit()          //Constrain to fit inside parent text view
    placeholder.tintColor = UIColor.clear //Unused in textviews. Can host our 'tag'
    placeholder.frame.origin = CGPoint(x: 5, y: 0) //Don't cover I-beam cursor
    placeholder.delegate = delegate  //Use as cache for caller's delegate 
    placeholder.font = UIFont.italicSystemFont(ofSize: (self.font?.pointSize)!)
    placeholder.text = placeholderText
    placeholder.textColor = color
    }
    func findPlaceholder() -> UITextView? { //find placeholder by its tag 
    for subview in self.subviews {
    if let textview = subview as? UITextView {
    if textview.tintColor == UIColor.clear { //sneaky tagging scheme
    return textview
    }
    }
    }
    return nil
    }
    /* 
    * Safely daisychain to caller delegate methods as appropriate...
    */
    public func textViewDidChange(_ textView: UITextView) { //←  need this delegate method
    if let placeholder = findPlaceholder() {
    placeholder.isHidden = !self.text.isEmpty //← ... to do this
    placeholder.delegate?.textViewDidChange?(textView)
    } 
    }
    /* 
    * Since we're becoming a delegate on behalf of this placeholder-enabled
    * text view instance, we must forward *all* that protocol's activity expected
    * by the instance, not just the particular optional protocol method we need to
    * intercept, above.
    */
    public func textViewDidEndEditing(_ textView: UITextView) {
    if let placeholder = findPlaceholder() {
    placeholder.delegate?.textViewDidEndEditing?(textView)
    } 
    }
    public func textViewDidBeginEditing(_ textView: UITextView) {
    if let placeholder = findPlaceholder() {
    placeholder.delegate?.textViewDidBeginEditing?(textView)
    } 
    }
    public  func textViewDidChangeSelection(_ textView: UITextView) {
    if let placeholder = findPlaceholder() {
    placeholder.delegate?.textViewDidChangeSelection?(textView)
    } 
    }
    public func textViewShouldEndEditing(_ textView: UITextView) -> Bool {
    if let placeholder = findPlaceholder() {
    guard let retval = placeholder.delegate?.textViewShouldEndEditing?(textView) else {
    return true
    }
    return retval
    }
    return true
    }
    public func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
    if let placeholder = findPlaceholder() {
    guard let retval = placeholder.delegate?.textViewShouldBeginEditing?(textView) else {
    return true
    }
    return retval
    } 
    return true
    }
    public func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    if let placeholder = findPlaceholder() {
    guard let retval = placeholder.delegate?.textView?(textView, shouldChangeTextIn: range, replacementText: text) else {
    return true
    }
    return retval
    } 
    return true
    }
    public func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
    if let placeholder = findPlaceholder() {
    guard let retval = placeholder.delegate?.textView?(textView, shouldInteractWith: URL, in: characterRange, interaction:
    interaction) else {
    return true
    }
    return retval
    }
    return true
    }
    public func textView(_ textView: UITextView, shouldInteractWith textAttachment: NSTextAttachment, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
    if let placeholder = findPlaceholder() {
    guard let retval = placeholder.delegate?.textView?(textView, shouldInteractWith: textAttachment, in: characterRange, interaction: interaction) else {
    return true
    }
    return retval
    }
    return true
    }
    }

    1. Como una extensión de una esencial iOS clase como UITextView, es importante saber que este código ha ninguna interacción con cualquier textviews que no activan un marcador de posición, e.g textview instancias que no ha sido inicializado con una llamada addPlaceholder()

    2. Marcador de posición habilitada para texto vistas de forma transparente convertido en un UITextViewDelegate para el seguimiento de la cuenta de caracteres, para el control de marcador de posición de visibilidad. Si un delegado se pasa a addPlaceholder(), este código de margarita cadenas (es decir, hacia delante) delegado de las devoluciones de llamada de ese delegado.

    3. El autor está investigando maneras para inspeccionar el UITextViewDelegate protocolo de proxy y de forma automática, sin tener que codificar cada método. Que inocular el código de la firma del método de los cambios y los nuevos métodos que se agrega al protocolo.

  42. 2

    Otra solución

    import UIKit
    protocol PlaceholderTextViewDelegate: class {
    func placeholderTextViewDidChangeText(_ text: String)
    func placeholderTextViewDidEndEditing(_ text: String)
    }
    final class PlaceholderTextView: UITextView {
    weak var notifier: PlaceholderTextViewDelegate?
    var ignoreEnterAction: Bool = true
    var placeholder: String? {
    didSet {
    text = placeholder
    selectedRange = NSRange(location: 0, length: 0)
    }
    }
    var placeholderColor = UIColor.lightGray {
    didSet {
    if text == placeholder {
    textColor = placeholderColor
    }
    }
    }
    var normalTextColor = UIColor.lightGray
    var placeholderFont = UIFont.sfProRegular(28)
    fileprivate var placeholderLabel: UILabel?
    //MARK: - LifeCycle
    override var text: String? {
    didSet {
    if text == placeholder {
    textColor = placeholderColor
    } else {
    textColor = normalTextColor
    }
    }
    }
    init() {
    super.init(frame: CGRect.zero, textContainer: nil)
    awakeFromNib()
    }
    required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    }
    override func awakeFromNib() {
    super.awakeFromNib()
    self.delegate = self
    }
    }
    extension PlaceholderTextView: UITextViewDelegate {
    //MARK: - UITextViewDelegate
    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    if text == "" && textView.text == placeholder {
    return false
    }
    if let placeholder = placeholder,
    textView.text == placeholder,
    range.location <= placeholder.count {
    textView.text = ""
    }
    if ignoreEnterAction && text == "\n" {
    textView.resignFirstResponder()
    return false
    }
    return true
    }
    func textViewDidChange(_ textView: UITextView) {
    if let placeholder = placeholder {
    textView.text = textView.text.replacingOccurrences(of: placeholder, with: "")
    }
    if let placeholder = placeholder,
    text?.isEmpty == true {
    text = placeholder
    textColor = placeholderColor
    selectedRange = NSRange(location: 0, length: 0)
    } else {
    textColor = normalTextColor
    }
    notifier?.placeholderTextViewDidChangeText(textView.text)
    }
    func textViewDidChangeSelection(_ textView: UITextView) {
    if let placeholder = placeholder,
    text == placeholder {
    selectedRange = NSRange(location: 0, length: 0)
    }
    }
    func textViewDidEndEditing(_ textView: UITextView) {
    notifier?.placeholderTextViewDidEndEditing(textView.text)
    if let placeholder = placeholder,
    text?.isEmpty == true {
    text = placeholder
    textColor = placeholderColor
    selectedRange = NSRange(location: 0, length: 0)
    } else {
    textColor = normalTextColor
    }
    }
    }

    resultado:

    Marcador de posición en UITextView

    • marcador no cambia después de escribir el texto.
  43. 1

    Si buscas una manera sencilla de lograr esto , intente con mi enfoque:

    - (BOOL)textViewShouldBeginEditing:(UITextView *)textView
    {
    if ([[textView text] isEqualToString:PLACE_HOLDER_TEXT]) {
    textView.text = @"";
    textView.textColor = [UIColor blackColor];
    }
    return YES;
    }
    -(BOOL)textViewShouldEndEditing:(UITextView *)textView
    {
    if ([[textView text] length] == 0) {
    textView.text = PLACE_HOLDER_TEXT;
    textView.textColor = [UIColor lightGrayColor];
    }
    return YES;
    }

    Sí, eso es PLACE_HOLDER_TEXT es un NSString que contiene su marcador de posición

  44. 1

    He encontrado una solución propia

    - (void)textViewDidBeginEditing:(UITextView *)textView
    {
    if ([textView.text isEqualToString:PLACEHOLDER_TEXT])
    {
    textView.textColor = [UIColor lightGrayColor];
    dispatch_async(dispatch_get_main_queue(), ^
    {
    textView.selectedRange = NSMakeRange(0, 0);
    });
    }
    else
    {
    textView.textColor = [UIColor blackColor];
    }
    [textView becomeFirstResponder];
    }
    - (void)textViewDidEndEditing:(UITextView *)textView
    {
    if ([textView.text isEqualToString:@""])
    {
    textView.text = PLACEHOLDER_TEXT;
    textView.textColor = [UIColor lightGrayColor];
    }
    [textView resignFirstResponder];
    }
    - (BOOL)textView:(UITextView *)textView
    shouldChangeTextInRange:(NSRange)range
    replacementText:(NSString *)text
    {
    if (range.location == 0 && range.length == [[textView text] length] && [text isEqualToString:@""])
    {
    textView.text = PLACEHOLDER_TEXT;
    textView.textColor = [UIColor lightGrayColor];
    dispatch_async(dispatch_get_main_queue(), ^
    {
    textView.selectedRange = NSMakeRange(0, 0);
    });
    return NO;
    }
    if ([textView.text isEqualToString:PLACEHOLDER_TEXT])
    {
    textView.text = @"";
    textView.textColor = [UIColor blackColor];
    }
    return YES;
    }
  45. 1

    Es aquí el código para swift 3.1

    Código Original por Jason George en la primera respuesta.

    No olvide ajustar su clase personalizada para TextView en el interface builder para UIPlaceHolderTextView y, a continuación, establezca marcador de posición de marcador de posición y propiedades.

    import UIKit
    @IBDesignable
    class UIPlaceHolderTextView: UITextView {
    @IBInspectable var placeholder: String = ""
    @IBInspectable var placeholderColor: UIColor = UIColor.lightGray
    private let uiPlaceholderTextChangedAnimationDuration: Double = 0.05
    private let defaultTagValue = 999
    private var placeHolderLabel: UILabel?
    override func awakeFromNib() {
    super.awakeFromNib()
    NotificationCenter.default.addObserver(
    self,
    selector: #selector(textChanged),
    name: NSNotification.Name.UITextViewTextDidChange,
    object: nil
    )
    }
    override init(frame: CGRect, textContainer: NSTextContainer?) {
    super.init(frame: frame, textContainer: textContainer)
    NotificationCenter.default.addObserver(
    self,
    selector: #selector(textChanged),
    name: NSNotification.Name.UITextViewTextDidChange,
    object: nil
    )
    }
    required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    NotificationCenter.default.addObserver(
    self,
    selector: #selector(textChanged),
    name: NSNotification.Name.UITextViewTextDidChange,
    object: nil
    )
    }
    deinit {
    NotificationCenter.default.removeObserver(
    self,
    name: NSNotification.Name.UITextViewTextDidChange,
    object: nil
    )
    }
    @objc private func textChanged() {
    guard !placeholder.isEmpty else {
    return
    }
    UIView.animate(withDuration: uiPlaceholderTextChangedAnimationDuration) {
    if self.text.isEmpty {
    self.viewWithTag(self.defaultTagValue)?.alpha = CGFloat(1.0)
    }
    else {
    self.viewWithTag(self.defaultTagValue)?.alpha = CGFloat(0.0)
    }
    }
    }
    override var text: String! {
    didSet{
    super.text = text
    textChanged()
    }
    }
    override func draw(_ rect: CGRect) {
    if !placeholder.isEmpty {
    if placeHolderLabel == nil {
    placeHolderLabel = UILabel.init(frame: CGRect(x: 0, y: 8, width: bounds.size.width - 16, height: 0))
    placeHolderLabel!.lineBreakMode = .byWordWrapping
    placeHolderLabel!.numberOfLines = 0
    placeHolderLabel!.font = font
    placeHolderLabel!.backgroundColor = UIColor.clear
    placeHolderLabel!.textColor = placeholderColor
    placeHolderLabel!.alpha = 0
    placeHolderLabel!.tag = defaultTagValue
    self.addSubview(placeHolderLabel!)
    }
    placeHolderLabel!.text = placeholder
    placeHolderLabel!.sizeToFit()
    self.sendSubview(toBack: placeHolderLabel!)
    if text.isEmpty && !placeholder.isEmpty {
    viewWithTag(defaultTagValue)?.alpha = 1.0
    }
    }
    super.draw(rect)
    }
    }
  46. 1

    He seguido el código desde este enlace. Sólo hay 7 pasos fáciles. Se añade un UILabel para el textView y oculta/muestra la etiqueta cuando se escribe texto o eliminado de la textView a través de la textView del textViewDidChangeSelection(_ textView: UITextView) método de delegado. Yo pongo los pasos a seguir en los comentarios sobre el código.

    //1. make sure to include the UITextViewDelegate
    class YourClass: UITextViewDelegate {
    @IBOutlet weak var textView : UITextView!
    //2. create placeholder textLabel
    let placeHolderTextLabel: UILabel = {
    let placeholderLabel = UILabel()
    placeholderLabel.text = "Placeholder text..."
    placeholderLabel.sizeToFit()
    placeholderLabel.textColor = UIColor.lightGray
    return placeholderLabel
    }()
    override func viewDidLoad() {
    super.viewDidLoad()
    //3. set textView delegate
    textView.delegate = self
    configurePlaceholderTextLabel()
    }
    func configurePlaceholderTextLabel() {
    //4. add placeholder label to textView, set it's frame and font
    textView.addSubview(placeHolderTextLabel)
    placeHolderTextLabel.frame.origin = CGPoint(x: 5, y: (textView.font?.pointSize)! / 2)
    placeHolderTextLabel.font = UIFont.systemFont(ofSize: (textView.font?.pointSize)!)
    //5. decide wether the placeHolderTextLabel is hidden or not depending on if there is or isn't text inside the textView
    placeHolderTextLabel.isHidden = !textView.text.isEmpty
    }
    //6. implement textView delegate method to update the placeHolderTextLabel when the text is changed
    func textViewDidChangeSelection(_ textView: UITextView) {
    //7. decide wether the placeHolderTextLabel is hidden or not depending on if there is or isn't text inside the textView when text in textView is changed
    placeHolderTextLabel.isHidden = !textView.text.isEmpty
    }
    }
  47. 0

    Más simple y aún contando con el texto introducido por el usuario en algún momento

    BOOL placeHolderTextVisible;

    sobre viewDidLoad, establece a YES (o DidMoveToSuperview, o awakeFromNib)

    a continuación, en
    – (BOOL) textView:(UITextView*)textView shouldBeginEditing

        - (BOOL)textViewShouldBeginEditing:(UITextView *)textView;
    {
    if (placeHolderTextVisible) {
    placeHolderTextVisible = NO;
    textView.text = @"";
    }
    return YES;
    }
    • No es la solución a todos – después de tocar UITextView marcador de posición desaparece y no aparece nunca la espalda.
    • El usuario podrá olvidar que puede escribir si no se borre el texto?
    • El símbolo de intercalación es visible explicando el usuario puede escribir.
  48. 0

    Jason respuesta se ve un poco apagado en iOS7, solucionarlo por ajustar la compensación de _placeHolderLabel:

    - (void)drawRect:(CGRect)rect
    {
    if( [[self placeholder] length] > 0 )
    {
    if (_placeHolderLabel == nil )
    {
    if ([[UIDevice currentDevice].systemVersion floatValue] >= 7)
    _placeHolderLabel = [[UILabel alloc] initWithFrame:CGRectMake(4,8,self.bounds.size.width - 8,0)];
    else
    _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];
    }
  49. 0

    Sólo he descubierto que a partir de iOS 10 ahora usted puede realmente lanzar un UITextView a un método como una UITextField y en el método del marcador de posición. Justo probado y funciona sin tener que subclase UITextView.

    Este es un ejemplo de lo que funcionó para mí:

    -(void)customizeTextField:(UITextField *)textField placeholder:(NSString *)pText withColor:(UIColor *)pTextColor{
    textField.attributedPlaceholder = [[NSAttributedString alloc]
    initWithString:pText
    attributes:@{NSForegroundColorAttributeName:pTextColor}];
    }

    Y usarlo para una UITextView sólo tienes que pasar al método utilizando un molde como este:

    [self customizeTextField:(UITextField*)_myTextView placeholder:@"Placeholder" withColor:[UIColor blackColor]];

    N. B: Después de una prueba he encontrado que la solución funciona bien también en iOS9.x pero a causa de un accidente en iOS8.x

  50. 0

    Después de mirar a través de (y probar) la mayoría de las soluciones propuestas a este aparentemente obvio -, sino de la falta de función de UITextView, el ‘mejor’ más cercano que encontré fue que a partir de BobDickinson. Pero que no me gustó tener que recurrir a toda una nueva subclase [prefiero caer en las categorías de tales sencillo y funcional adiciones], ni que es interceptado UITextViewDelegate métodos, que es, probablemente, va a confundir su UITextView código de control. Así que aquí está mi opinión sobre una gota en la categoría que va a funcionar en cualquier existentes UITextView ejemplo…

    #import <objc/runtime.h>
    //Private subclass needed to override placeholderRectForBounds: to correctly position placeholder
    @interface _TextField : UITextField
    @property UIEdgeInsets insets;
    @end
    @implementation _TextField
    - (CGRect)placeholderRectForBounds:(CGRect)bounds
    {
    CGRect rect = [super placeholderRectForBounds:bounds];
    return UIEdgeInsetsInsetRect(rect, _insets);
    }
    @end
    @implementation UITextView (Placeholder)
    static const void *KEY;
    - (void)setPlaceholder:(NSString *)placeholder
    {
    _TextField *textField = objc_getAssociatedObject(self, &KEY);
    if (!textField) {
    textField = [_TextField.alloc initWithFrame:self.bounds];
    textField.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    textField.userInteractionEnabled = NO;
    textField.font = self.font;
    textField.contentVerticalAlignment = UIControlContentVerticalAlignmentTop;
    textField.insets = UIEdgeInsetsMake(self.textContainerInset.top,
    self.textContainerInset.left + self.textContainer.lineFragmentPadding,
    self.textContainerInset.bottom,
    self.textContainerInset.right);
    [self addSubview:textField];
    [self sendSubviewToBack:textField];
    objc_setAssociatedObject(self, &KEY, textField, OBJC_ASSOCIATION_RETAIN);
    [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(updatePlaceholder:) name:UITextViewTextDidChangeNotification object:nil];
    }
    textField.placeholder = placeholder;
    }
    - (NSString*)placeholder
    {
    UITextField *textField = objc_getAssociatedObject(self, &KEY);
    return textField.placeholder;
    }
    - (void)updatePlaceholder:(NSNotification *)notification
    {
    UITextField *textField = objc_getAssociatedObject(self, &KEY);
    textField.font = self.font;
    [textField setAlpha:self.text.length? 0 : 1];
    }
    @end

    Su simple de usar, sólo el obvio

    UITextView *myTextView = UITextView.new;
    ...
    myTextView.placeholder = @"enter text here";

    Funciona mediante la adición de un UITextField – en el lugar correcto – detrás de su UITextView, y la explotación de es marcador de lugar (por lo tanto, usted no tiene que preocuparse acerca de cómo obtener el color correcto, etc), entonces la escucha para recibir notificaciones cada vez que su UITextView se cambia para mostrar/ocultar esta UITextField (y por lo tanto no interfiere con su UITextViewDelegate llamadas). Y no hay magia de los números involucrados… 🙂

    La objc_setAssociatedObject()/objc_getAssociatedObject() es para evitar tener que subclase UITextView. [Por desgracia, la posición de la UITextField correctamente, es necesario introducir un ‘privado’ subclase, para reemplazar placeholderRectForBounds:]

    Adaptado de BobDickinson la rápida respuesta.

  51. 0

    Simplemente crear @IBDesignable subclase de su UITextView:

    @IBDesignable class AttributedTextView: UITextView {
    private let placeholderLabel = UILabel()
    @IBInspectable var placeholder: String = "" {
    didSet {
    setupPlaceholderLabelIfNeeded()
    textViewDidChange()
    }
    }
    override var text: String! {
    didSet {
    textViewDidChange()
    }
    }
    //MARK: - Initialization
    override func awakeFromNib() {
    super.awakeFromNib()
    setupPlaceholderLabelIfNeeded()
    NotificationCenter.default.addObserver(self, selector: #selector(textViewDidChange), name: .UITextViewTextDidChange, object: nil)
    }
    //MARK: - Deinitialization
    deinit {
    NotificationCenter.default.removeObserver(self)
    }
    //MARK: - Internal
    func textViewDidChange() {
    placeholderLabel.isHidden = !text.isEmpty
    layoutIfNeeded()
    }
    //MARK: - Private
    private func setupPlaceholderLabelIfNeeded() {
    placeholderLabel.removeFromSuperview()
    placeholderLabel.frame = CGRect(x: 0, y: 8, width: frame.size.width, height: 0)
    placeholderLabel.textColor = UIColor.lightGray
    placeholderLabel.text = placeholder
    placeholderLabel.sizeToFit()
    insertSubview(placeholderLabel, at: 0)
    }
    }

    y, a continuación, simplemente la configuración de su marcador de posición en identidad inspector:

    Marcador de posición en UITextView

  52. 0

    Swift 3.1

    Después de intentar todos swift respuestas, esta respuesta me habría ahorrado 3 horas de investigación. Espero que esto ayude.

    1. Asegúrese de que su textField (no importa el nombre personalizado que tiene) es que apunta a su delegado en el Guión gráfico y tiene un @IBOutlet con yourCustomTextField

    2. Añadir a viewDidLoad() la siguiente, aparecerá cuando se carga la vista:

    Me muestran lo que parece ser un marcador de posición:

    yourCustomTextField = "Start typing..." 
    yourCustomTextField.textColor = .lightGray
    1. Fuera de la viewDidLoad pero dentro de la misma clase, agregue la siguiente declaración: UIViewController, UITextViewDelegate, UINavigationControllerDelegate

    Este código hará que yourCustomTextField desaparece al escribir en el campo de texto:

    func textViewDidBeginEditing (_ textView: UITextView) { 
    if (textView.text == "Start typing...") {
    textView.text = ""
    textView.textColor = .black
    }
    textView.becomeFirstResponder()
    }
    func textViewDidEndEditing(_ textView: UITextView) {
    if (textView.text == "") {
    textView.text = "Start typing..."
    textView.textColor = .lightGray
    }
    textView.resignFirstResponder()
    }
  53. 0

    Basado en algunas de las grandes sugerencias aquí ya, yo era capaz de reunir las siguientes ligero, Interface Builder-compatible subclase de UITextView, que:

    • Incluye configurable texto de marcador de posición, de estilo al igual que la de UITextField.
    • No requiere ningún subvistas o restricciones.
    • No requiere ningún tipo de delegación o de otros comportamientos de la ViewController.
    • No requiere ningún tipo de notificaciones.
    • Mantiene que el texto totalmente separadas de cualquier fuera de clases buscando en el campo de la text propiedad.

    Cualquiera de las sugerencias de mejora son bienvenidas, sobre todo si hay alguna manera de que tire de iOS color de marcador de posición a través de programación, en lugar de la codificación de la misma.

    Swift v5:

    import UIKit
    @IBDesignable class TextViewWithPlaceholder: UITextView {
    override var text: String! { //Ensures that the placeholder text is never returned as the field's text
    get {
    if showingPlaceholder {
    return "" //When showing the placeholder, there's no real text to return
    } else { return super.text }
    }
    set { super.text = newValue }
    }
    @IBInspectable var placeholderText: String = ""
    @IBInspectable var placeholderTextColor: UIColor = UIColor(red: 0.78, green: 0.78, blue: 0.80, alpha: 1.0) //Standard iOS placeholder color (#C7C7CD). See https://stackoverflow.com/questions/31057746/whats-the-default-color-for-placeholder-text-in-uitextfield
    private var showingPlaceholder: Bool = true //Keeps track of whether the field is currently showing a placeholder
    override func didMoveToWindow() {
    super.didMoveToWindow()
    if text.isEmpty {
    showPlaceholderText() //Load up the placeholder text when first appearing, but not if coming back to a view where text was already entered
    }
    }
    override func becomeFirstResponder() -> Bool {
    //If the current text is the placeholder, remove it
    if showingPlaceholder {
    text = nil
    textColor = nil //Put the text back to the default, unmodified color
    showingPlaceholder = false
    }
    return super.becomeFirstResponder()
    }
    override func resignFirstResponder() -> Bool {
    //If there's no text, put the placeholder back
    if text.isEmpty {
    showPlaceholderText()
    }
    return super.resignFirstResponder()
    }
    private func showPlaceholderText() {
    showingPlaceholder = true
    textColor = placeholderTextColor
    text = placeholderText
    }
    }
  54. -1

    Sólo puede establecer una etiqueta en el textview.

    MyUITextView.h

    @interface MyUITextView : UITextView {
    UILabel* _placeholderLabel;
    }
    @property(nonatomic, assign)NSString *placeholder;

    MyUITextView.m

    @implementation MyUITextView
    - (id)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
    //Create placeholder
    viewFrame = CGRectMake(0, 0, frame.size.width, 15);
    _placeholderLabel = [[UILabel alloc] initWithFrame:viewFrame];
    _placeholderLabel.textColor = [UIColor lightGrayColor];
    [self addSubview:_placeholderLabel];
    //Add text changed notification 
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChanged:) name:UITextViewTextDidChangeNotification object:nil];
    }
    return self;
    }
    - (void)setPlaceholder:(NSString *)placeholder {
    _placeholderLabel.text = placeholder;
    }
    - (NSString*)placeholder {
    return _placeholderLabel.text;
    }
    #pragma mark UITextViewTextDidChangeNotification
    - (void)textChanged:(NSNotification *)notification {
    _placeholderLabel.hidden = ([self.text lenght] == 0);
    }
    @end
  55. -1

    Sencilla clase para apoyar el icono de attribted marcadores de posición en UITextView PlaceholderTextView

    @IBOutlet weak var tvMessage: PlaceholderTextView!
    // TODO: - Create Icon Text Attachment
    let icon: NSTextAttachment = NSTextAttachment()
    icon.image = UIImage(named: "paper-plane")
    let iconString = NSMutableAttributedString(attributedString: NSAttributedString(attachment: icon))
    tvMessage.icon = icon
    // TODO: - Attributes
    let textColor = UIColor.gray
    let lightFont = UIFont(name: "Helvetica-Light", size: tvMessage.font!.pointSize)
    let italicFont = UIFont(name: "Helvetica-LightOblique", size: tvMessage.font!.pointSize)
    // TODO: - Placeholder Attributed String
    let message = NSAttributedString(string: " " + "Personal Message", attributes: [ NSFontAttributeName: lightFont!,   NSForegroundColorAttributeName: textColor])
    iconString.append(message)
    //TODO: - Italic Placeholder Part
    let option = NSAttributedString(string: " " + "Optional", attributes: [ NSFontAttributeName: italicFont!, NSForegroundColorAttributeName: textColor])
    iconString.append(option)
    tvMessage.attributedPlaceHolder = iconString
    tvMessage.layoutSubviews()

    Marcador de posición en UITextView
    Marcador de posición en UITextView

  56. -1

    El método más fácil de modificar el texto del marcador de posición de color es a través de la XCode guión gráfico de interface builder. Seleccione el UITextField de interés y abrir la identidad del inspector de la derecha. Haga clic en el símbolo más en el Definido por el Usuario de tiempo de ejecución de los Atributos y añadir una nueva fila con la Ruta de la Clave como _placeholderLabel.textColor, Tipo como el Color y el Valor para el color deseado.

    • No tiene nada que ver con la cuestión o incluso un UITextView.
  57. -4

    Yo era capaz de hacer un «marcador de posición» para un UITextView con MUCHO menos código. Esto es lo que hice:

    UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(60, 800, 200, 60)];
    textView.text = @"Write characters here...";
    textView.textColor=[UIColor grayColor];
    textView.font = [UIFont fontWithName:@"Hevlatica" size:15];
    textView.delegate=self;

    Supongo que no es un verdadero marcador de posición porque tienes que borrar el texto antes de escribir, pero que podría ayudar si usted quería algo un poco más simple.

    • Creo que esta respuesta es injustamente votada abajo. Esta es una bonita e inteligente solución. Además, anulando drawRect es bastante caro. A pesar de que más es necesario introducir el código para ocultar y posiblemente la vista de texto sobre cómo cambiar el tamaño, yo creo que merece la ganancia de rendimiento.

Dejar respuesta

Please enter your comment!
Please enter your name here