titletextattributes color bar ios swift uitextview placeholder

ios - color - Vista de texto(UITextView) Marcador de posición Swift



uinavigationitem title color (30)

Marcador de posición flotante

Es simple, seguro y confiable colocar una etiqueta de marcador de posición sobre una vista de texto, establecer su fuente, color y administrar la visibilidad del marcador de posición mediante el seguimiento de los cambios en el recuento de caracteres de la vista de texto.

Swift 3:

class NotesViewController : UIViewController, UITextViewDelegate { @IBOutlet var textView : UITextView! var placeholderLabel : UILabel! override func viewDidLoad() { super.viewDidLoad() textView.delegate = self placeholderLabel = UILabel() placeholderLabel.text = "Enter some text..." placeholderLabel.font = UIFont.italicSystemFont(ofSize: (textView.font?.pointSize)!) placeholderLabel.sizeToFit() textView.addSubview(placeholderLabel) placeholderLabel.frame.origin = CGPoint(x: 5, y: (textView.font?.pointSize)! / 2) placeholderLabel.textColor = UIColor.lightGray placeholderLabel.isHidden = !textView.text.isEmpty } func textViewDidChange(_ textView: UITextView) { placeholderLabel.isHidden = !textView.text.isEmpty } }

Swift 2: igual, excepto: italicSystemFontOfSize(textView.font.pointSize) , UIColor.lightGrayColor

Estoy haciendo una aplicación que usa un UITextView . Ahora quiero que la Vista de texto tenga un marcador de posición similar al que puede establecer para un Campo de texto. ¿Cómo lograrías esto usando Swift?

¿Alguien sabe como hacer esto?


Respuesta rápida

Aquí está la clase personalizada, que anima el marcador de posición.

extension UITextViewPlaceholder where Self: UIViewController { // Use this in ViewController''s ViewDidLoad method. func addPlaceholder(text: String, toTextView: UITextView, font: UIFont? = nil) { placeholderLabel = UILabel() placeholderLabel.text = text placeholderLabel.font = font ?? UIFont.italicSystemFont(ofSize: (toTextView.font?.pointSize)!) placeholderLabel.sizeToFit() toTextView.addSubview(placeholderLabel) placeholderLabel.frame.origin = CGPoint(x: 5, y: (toTextView.font?.pointSize)! / 2) placeholderLabel.textColor = UIColor.lightGray placeholderLabel.isHidden = !toTextView.text.isEmpty } // Use this function in the ViewController''s textViewDidChange delegate method. func textViewWithPlaceholderDidChange(_ textView: UITextView) { placeholderLabel.isHidden = !textView.text.isEmpty } }


Aquí está mi forma de resolver este problema ( Swift 4 ):

La idea era hacer la solución más simple posible que permita utilizar marcadores de posición de diferentes colores, cambiar el tamaño al tamaño de los marcadores de posición, no sobrescribirá delegate mientras tanto, manteniendo todas las UITextView funciones funcionando como se esperaba.

import UIKit class PlaceholderTextView: UITextView { var placeholderColor: UIColor = .lightGray var defaultTextColor: UIColor = .black private var isShowingPlaceholder = false { didSet { if isShowingPlaceholder { text = placeholder textColor = placeholderColor } else { textColor = defaultTextColor } } } var placeholder: String? { didSet { isShowingPlaceholder = !hasText } } @objc private func textViewDidBeginEditing(notification: Notification) { textColor = defaultTextColor if isShowingPlaceholder { text = nil } } @objc private func textViewDidEndEditing(notification: Notification) { isShowingPlaceholder = !hasText } // MARK: - Construction - override init(frame: CGRect, textContainer: NSTextContainer?) { super.init(frame: frame, textContainer: textContainer) setup() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setup() } private func setup() { NotificationCenter.default.addObserver(self, selector: #selector(textViewDidBeginEditing(notification:)), name: UITextView.textDidBeginEditingNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(textViewDidEndEditing(notification:)), name: UITextView.textDidEndEditingNotification, object: nil) } // MARK: - Destruction - deinit { NotificationCenter.default.removeObserver(self) } }


En swift2.2:

public class 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) }

}

En swift3:

import UIKit

clase 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() { NotificationCenter.default.addObserver(self, selector: #selector(textDidChange), name: NSNotification.Name.UITextViewTextDidChange, object: nil) placeholderLabel.font = font placeholderLabel.textColor = placeholderColor placeholderLabel.textAlignment = textAlignment placeholderLabel.text = placeholder placeholderLabel.numberOfLines = 0 placeholderLabel.backgroundColor = UIColor.clear placeholderLabel.translatesAutoresizingMaskIntoConstraints = false addSubview(placeholderLabel) updateConstraintsForPlaceholderLabel() } private func updateConstraintsForPlaceholderLabel() { var newConstraints = NSLayoutConstraint.constraints(withVisualFormat: "H:|-(/(textContainerInset.left + textContainer.lineFragmentPadding))-[placeholder]", options: [], metrics: nil, views: ["placeholder": placeholderLabel]) newConstraints += NSLayoutConstraint.constraints(withVisualFormat: "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.isHidden = !text.isEmpty } public override func layoutSubviews() { super.layoutSubviews() placeholderLabel.preferredMaxLayoutWidth = textContainer.size.width - textContainer.lineFragmentPadding * 2.0 } deinit { NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UITextViewTextDidChange, object: nil) }

}

Escribí una clase en rápido. Debe importar esta clase cuando sea necesario.


Esta es mi solución lista para usar si está trabajando con múltiples vistas de texto

pod ''UITextView+Placeholder'', ''~> 1.2''


Me gusta la solución de @ nerdist. Basado en eso, creé una extensión para UITextView :

import Foundation import UIKit extension UITextView { private func add(_ placeholder: UILabel) { for view in self.subviews { if let lbl = view as? UILabel { if lbl.text == placeholder.text { lbl.removeFromSuperview() } } } self.addSubview(placeholder) } func addPlaceholder(_ placeholder: UILabel?) { if let ph = placeholder { ph.numberOfLines = 0 // support for multiple lines ph.font = UIFont.italicSystemFont(ofSize: (self.font?.pointSize)!) ph.sizeToFit() self.add(ph) ph.frame.origin = CGPoint(x: 5, y: (self.font?.pointSize)! / 2) ph.textColor = UIColor(white: 0, alpha: 0.3) updateVisibility(ph) } } func updateVisibility(_ placeHolder: UILabel?) { if let ph = placeHolder { ph.isHidden = !self.text.isEmpty } } }

En una clase ViewController, por ejemplo, así es como lo uso:

class MyViewController: UIViewController, UITextViewDelegate { private var notePlaceholder: UILabel! @IBOutlet weak var txtNote: UITextView! ... // UIViewController override func viewDidLoad() { notePlaceholder = UILabel() notePlaceholder.text = "title/nsubtitle/nmore..." txtNote.addPlaceholder(notePlaceholder) ... } // UITextViewDelegate func textViewDidChange(_ textView: UITextView) { txtNote.updateVisbility(notePlaceholder) ... }

Marcador de posición en UITextview!

ACTUALIZACIÓN :

En caso de que cambie el texto de la vista de texto en el código, recuerde llamar al método updateVisibitly para ocultar el marcador de posición:

txtNote.text = "something in code" txtNote.updateVisibility(self.notePlaceholder) // hide placeholder if text is not empty.

Para evitar que el marcador de posición se agregue más de una vez, add() se agrega una función privada extension .


No existe tal propiedad en ios para agregar marcador de posición directamente en TextView, sino que puede agregar una etiqueta y mostrar / ocultar el cambio en textView. SWIFT 2.0 y asegúrese de implementar el textviewdelegate

func textViewDidChange(TextView: UITextView) { if txtShortDescription.text == "" { self.lblShortDescription.hidden = false } else { self.lblShortDescription.hidden = true } }


No puedo agregar comentarios debido a la reputación. agregue una necesidad más de delegado en la respuesta @clearlight.

func textViewDidBeginEditing(_ textView: UITextView) { cell.placeholderLabel.isHidden = !textView.text.isEmpty }

es necesidad

porque textViewDidChange no se llama primera vez


Nuestra solución evita el robo con las propiedades UITextView text y textColor , lo cual es útil si mantiene un contador de caracteres.

Es sencillo:

1) Cree un maniquí UITextView en Storyboard con las mismas propiedades que el maestro UITextView . Asigne texto de marcador de posición al texto ficticio.

2) Alinee los bordes superior, izquierdo y derecho de los dos UITextViews.

3) Coloque el maniquí detrás del maestro.

4) Anule la textViewDidChange(textView:) función de delegado del maestro y muestre el ficticio si el maestro tiene 0 caracteres. De lo contrario, muestra al maestro.

Esto supone que ambos UITextViews tienen fondos transparentes. Si no lo hacen, coloque el muñeco en la parte superior cuando haya 0 caracteres y empújelo debajo cuando haya> 0 caracteres. También deberá intercambiar los respondedores para asegurarse de que el cursor siga a la derecha UITextView .


Swift: escribí una clase que heredó UITextView y agregué un UILabel como una subvista para actuar como marcador de posición.

import UIKit @IBDesignable class HintedTextView: UITextView { @IBInspectable var hintText: String = "hintText" { didSet{ hintLabel.text = hintText } } private lazy var hintLabel: UILabel = { let label = UILabel() label.font = UIFont.systemFontOfSize(16) label.textColor = UIColor.lightGrayColor() label.translatesAutoresizingMaskIntoConstraints = false return label }() override init(frame: CGRect, textContainer: NSTextContainer?) { super.init(frame: frame, textContainer: textContainer) setupView() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setupView() } override func prepareForInterfaceBuilder() { super.prepareForInterfaceBuilder() setupView() } private func setupView() { translatesAutoresizingMaskIntoConstraints = false delegate = self font = UIFont.systemFontOfSize(16) addSubview(hintLabel) NSLayoutConstraint.activateConstraints([ hintLabel.leftAnchor.constraintEqualToAnchor(leftAnchor, constant: 4), hintLabel.rightAnchor.constraintEqualToAnchor(rightAnchor, constant: 8), hintLabel.topAnchor.constraintEqualToAnchor(topAnchor, constant: 4), hintLabel.heightAnchor.constraintEqualToConstant(30) ]) } override func layoutSubviews() { super.layoutSubviews() setupView() } }


Tuve que enviar la cola para que mi texto de marcador de posición reapareciera una vez que se completara la edición.

func textViewDidBeginEditing(_ textView: UITextView) { if textView.text == "Description" { textView.text = nil } } func textViewDidEndEditing(_ textView: UITextView) { if textView.text.isEmpty { DispatchQueue.main.async { textView.text = "Description" } } }


Versión de protocolo de la respuesta de anterior, porque los protocolos son excelentes. Pásalo donde quieras. ¡Remojar!

func textViewDidBeginEditing(_ textView: UITextView) { if (commentsTextView.text == "Type Your Comments") { commentsTextView.text = nil commentsTextView.textColor = UIColor.darkGray } } func textViewDidEndEditing(_ textView: UITextView) { if commentsTextView.text.isEmpty { commentsTextView.text = "Type Your Comments" commentsTextView.textColor = UIColor.darkGray } textView.resignFirstResponder() }


no, no hay ningún marcador de posición disponible para la vista de texto. debe colocar una etiqueta encima cuando el usuario ingresa en la vista de texto y luego ocultarlo o establecerlo por defecto cuando el usuario ingresa eliminar todos los valores.


Al contrario de casi todas las respuestas en esta publicación, UITextView tiene una propiedad de marcador de posición. Por razones más allá de mi comprensión, solo se expone en IB, como tal:

<userDefinedRuntimeAttributes> <userDefinedRuntimeAttribute type="string" keyPath="placeholder" value="My Placeholder"/> </userDefinedRuntimeAttributes>

Entonces, si está utilizando guiones gráficos y un marcador de posición estático será suficiente, solo configure la propiedad en el inspector.

También puede establecer esta propiedad en un código como este:

textView.setValue("My Placeholder", forKeyPath: "placeholder")

Está nublado en cuanto al clima, se accede a través de una API privada, ya que la propiedad está expuesta.

No he intentado enviar con este método. Pero lo enviaré de esta manera en breve y actualizaré esta respuesta en consecuencia.

ACTUALIZAR:

He enviado este código en varias versiones sin problemas de Apple.


Basado en algunas de las excelentes sugerencias aquí, pude reunir la siguiente subclase de UITextView , UITextView y compatible con Interface-Builder, que:

  • Incluye texto de marcador de posición configurable, con el mismo estilo que UITextField .
  • No requiere subvistas o restricciones adicionales.
  • No requiere ninguna delegación u otro comportamiento del ViewController.
  • No requiere ninguna notificación.
  • Mantiene ese texto completamente separado de las clases externas que miran la propiedad de text del campo.

Cualquier sugerencia de mejora es bienvenida, especialmente si hay alguna forma de extraer el color del marcador de posición de iOS mediante programación, en lugar de codificarlo.

Swift v5:

txtVw!.autocorrectionType = UITextAutocorrectionType.No txtVw!.text = "Write your Placeholder" txtVw!.textColor = UIColor.lightGrayColor() func textViewDidBeginEditing(textView: UITextView) { if (txtVw?.text == "Write your Placeholder") { txtVw!.text = nil txtVw!.textColor = UIColor.blackColor() } } func textViewDidEndEditing(textView: UITextView) { if txtVw!.text.isEmpty { txtVw!.text = "Write your Placeholder" txtVw!.textColor = UIColor.lightGrayColor() } textView.resignFirstResponder() }


Esto es lo que estoy usando para este trabajo realizado.

- (void)customInit { self.contentMode = UIViewContentModeRedraw; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChanged:) name:UITextViewTextDidChangeNotification object:nil]; } - (void)textChanged:(NSNotification *)notification { if (notification.object == self) { if(self.textStorage.length != 0 || !self.textStorage.length) { [self setNeedsDisplay]; } } } #pragma mark - Setters - (void)setPlaceholderText:(NSString *)placeholderText withFont:(UIFont *)font { self.placeholderText = placeholderText; self.placeholderTextFont = font; } - (void)drawRect:(CGRect)rect { [super drawRect:rect]; [[UIColor lightGrayColor] setFill]; if (self.textStorage.length != 0) { return; } CGRect inset = CGRectInset(rect, 8, 8);//Default rect insets for textView NSDictionary *attributes = @{NSFontAttributeName: self.placeholderTextFont, NSForegroundColorAttributeName: [UIColor grayColor]}; [self.placeholderText drawInRect:inset withAttributes:attributes]; }`

Sé que hay varios enfoques similares a este, pero los beneficios de este son:

  • Puede establecer texto de marcador de posición, tamaño de fuente y color en IB .
  • Ya no muestra la advertencia de "La vista de desplazamiento tiene contenido desplazable ambiguo " en IB.
  • Agregue animación para mostrar / ocultar el marcador de posición.

Hice esto usando dos vistas de texto diferentes:

  1. Uno en segundo plano que se utiliza como marcador de posición.
  2. Uno en primer plano (con un fondo transparente) que el usuario realmente escribe.

La idea es que una vez que el usuario comienza a escribir cosas en la vista de primer plano, el marcador de posición en el fondo desaparece (y vuelve a aparecer si el usuario elimina todo). Por lo tanto, se comporta exactamente como un marcador de posición para el campo de texto de una sola línea.

Aquí está el código que usé para ello. Tenga en cuenta que descriptionField es el campo que escribe el usuario y descriptionPlaceholder es el que está en segundo plano.

yourTextView.placeholder = "Placeholder" extension UITextView :UITextViewDelegate { /// Resize the placeholder when the UITextView bounds change override open var bounds: CGRect { didSet { self.resizePlaceholder() } } /// The UITextView placeholder text public var placeholder: String? { get { var placeholderText: String? if let placeholderLabel = self.viewWithTag(100) as? UILabel { placeholderText = placeholderLabel.text } return placeholderText } set { if let placeholderLabel = self.viewWithTag(100) as! UILabel? { placeholderLabel.text = newValue placeholderLabel.sizeToFit() } else { self.addPlaceholder(newValue!) } } } /// When the UITextView did change, show or hide the label based on if the UITextView is empty or not /// /// - Parameter textView: The UITextView that got updated public func textViewDidChange(_ textView: UITextView) { if let placeholderLabel = self.viewWithTag(100) as? UILabel { placeholderLabel.isHidden = self.text.characters.count > 0 } } /// Resize the placeholder UILabel to make sure it''s in the same position as the UITextView text private func resizePlaceholder() { if let placeholderLabel = self.viewWithTag(100) as! UILabel? { let labelX = self.textContainer.lineFragmentPadding let labelY = self.textContainerInset.top - 2 let labelWidth = self.frame.width - (labelX * 2) let labelHeight = placeholderLabel.frame.height placeholderLabel.frame = CGRect(x: labelX, y: labelY, width: labelWidth, height: labelHeight) } } /// Adds a placeholder UILabel to this UITextView private func addPlaceholder(_ placeholderText: String) { let placeholderLabel = UILabel() placeholderLabel.text = placeholderText placeholderLabel.sizeToFit() placeholderLabel.font = self.font placeholderLabel.textColor = UIColor.lightGray placeholderLabel.tag = 100 placeholderLabel.isHidden = self.text.characters.count > 0 self.addSubview(placeholderLabel) self.resizePlaceholder() self.delegate = self } }


Me sorprende que nadie haya mencionado NSTextStorageDelegate . UITextViewDelegate métodos de UITextViewDelegate solo se activarán mediante la interacción del usuario, pero no mediante programación. Por ejemplo, cuando configura la propiedad de texto de una vista de text programación, deberá establecer la visibilidad del marcador de posición usted mismo, porque no se invocarán los métodos delegados.

Sin embargo, con el NSTextStorageDelegate textStorage(_:didProcessEditing:range:changeInLength:) , se le notificará cualquier cambio en el texto, incluso si se realiza mediante programación. Simplemente asígnelo así:

textView.textStorage.delegate = self

(En UITextView , esta propiedad de delegado es nil de forma predeterminada, por lo que no afectará a ningún comportamiento predeterminado).

UILabel con la técnica UILabel que @clearlight demuestra, uno puede envolver fácilmente toda la implementación de placeholder UITextView en una extensión.

extension UITextView { private class PlaceholderLabel: UILabel { } private var placeholderLabel: PlaceholderLabel { if let label = subviews.compactMap( { $0 as? PlaceholderLabel }).first { return label } else { let label = PlaceholderLabel(frame: .zero) label.font = font addSubview(label) return label } } @IBInspectable var placeholder: String { get { return subviews.compactMap( { $0 as? PlaceholderLabel }).first?.text ?? "" } set { let placeholderLabel = self.placeholderLabel placeholderLabel.text = newValue placeholderLabel.numberOfLines = 0 let width = frame.width - textContainer.lineFragmentPadding * 2 let size = placeholderLabel.sizeThatFits(CGSize(width: width, height: .greatestFiniteMagnitude)) placeholderLabel.frame.size.height = size.height placeholderLabel.frame.size.width = width placeholderLabel.frame.origin = CGPoint(x: textContainer.lineFragmentPadding, y: textContainerInset.top) textStorage.delegate = self } } } extension UITextView: NSTextStorageDelegate { public func textStorage(_ textStorage: NSTextStorage, didProcessEditing editedMask: NSTextStorageEditActions, range editedRange: NSRange, changeInLength delta: Int) { if editedMask.contains(.editedCharacters) { placeholderLabel.isHidden = !text.isEmpty } } }

Tenga en cuenta que el uso de una clase privada (anidada) llamada PlaceholderLabel . No tiene ninguna implementación en absoluto, pero nos proporciona una forma de identificar la etiqueta de marcador de posición, que es mucho más "rápida" que usar la propiedad de tag .

Con este enfoque, aún puede asignar el delegado de UITextView a otra persona.

Ni siquiera tiene que cambiar las clases de sus vistas de texto. Simplemente agregue las extensiones y podrá asignar una cadena de marcador de posición a cada UITextView en su proyecto, incluso en el Creador de interfaces.

Dejé de lado la implementación de una propiedad placeholderColor por razones de claridad, pero se puede implementar solo por unas pocas líneas más con una variable computada similar al placeholder de placeholder .


No sé por qué las personas complican tanto este problema ... Es bastante sencillo y sencillo. Aquí hay una subclase de UITextView que proporciona la funcionalidad solicitada.

func textViewShouldBeginEditing(textView: UITextView) -> Bool { // Set cursor to the beginning if placeholder is set if textView.textColor == UIColor.lightGrayColor() { textView.selectedTextRange = textView.textRangeFromPosition(textView.beginningOfDocument, toPosition: textView.beginningOfDocument) } return true } func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool { // Remove placeholder if textView.textColor == UIColor.lightGrayColor() && text.characters.count > 0 { textView.text = "" textView.textColor = UIColor.blackColor() } if text == "/n" { textView.resignFirstResponder() return false } return true } func textViewDidChange(textView: UITextView) { // Set placeholder if text is empty if textView.text.isEmpty { textView.text = NSLocalizedString("Hint", comment: "hint") textView.textColor = UIColor.lightGrayColor() textView.selectedTextRange = textView.textRangeFromPosition(textView.beginningOfDocument, toPosition: textView.beginningOfDocument) } } func textViewDidChangeSelection(textView: UITextView) { // Set cursor to the beginning if placeholder is set let firstPosition = textView.textRangeFromPosition(textView.beginningOfDocument, toPosition: textView.beginningOfDocument) // Do not change position recursively if textView.textColor == UIColor.lightGrayColor() && textView.selectedTextRange != firstPosition { textView.selectedTextRange = firstPosition } }



Swift 3.2

extension EditProfileVC:UITextViewDelegate{ func textViewDidBeginEditing(_ textView: UITextView) { if textView.textColor == UIColor.lightGray { textView.text = nil textView.textColor = UIColor.black } } func textViewDidEndEditing(_ textView: UITextView) { if textView.text.isEmpty { textView.text = "Placeholder" textView.textColor = UIColor.lightGray } } }

Primero, cuando el usuario comienza a editar la llamada textViewDidBeginEditing y luego verifica si el color del texto gris significa que el usuario no escribió nada, luego establece como textview nil y cambia el color a negro para los mensajes de texto del usuario.

Cuando el usuario finaliza la edición de textViewDidEndEditing es una llamada y comprueba si el usuario no escribe nada en la vista de texto y luego el texto se establece en color gris con el texto "PlaceHolder"


Traté de hacer el código conveniente a partir de la answer de .

extension UITextView{ func setPlaceholder() { let placeholderLabel = UILabel() placeholderLabel.text = "Enter some text..." placeholderLabel.font = UIFont.italicSystemFont(ofSize: (self.font?.pointSize)!) placeholderLabel.sizeToFit() placeholderLabel.tag = 222 placeholderLabel.frame.origin = CGPoint(x: 5, y: (self.font?.pointSize)! / 2) placeholderLabel.textColor = UIColor.lightGray placeholderLabel.isHidden = !self.text.isEmpty self.addSubview(placeholderLabel) } func checkPlaceholder() { let placeholderLabel = self.viewWithTag(222) as! UILabel placeholderLabel.isHidden = !self.text.isEmpty } }

uso

override func viewDidLoad() { textView.delegate = self textView.setPlaceholder() } func textViewDidChange(_ textView: UITextView) { textView.checkPlaceholder() }


Una solución más (Swift 3):

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://.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 } }

resultado


Una solución simple y rápida que funciona para mí es:

@IBDesignable class PlaceHolderTextView: UITextView { @IBInspectable var placeholder: String = "" { didSet{ updatePlaceHolder() } } @IBInspectable var placeholderColor: UIColor = UIColor.gray { didSet { updatePlaceHolder() } } private var originalTextColor = UIColor.darkText private var originalText: String = "" private func updatePlaceHolder() { if self.text == "" || self.text == placeholder { self.text = placeholder self.textColor = placeholderColor if let color = self.textColor { self.originalTextColor = color } self.originalText = "" } else { self.textColor = self.originalTextColor self.originalText = self.text } } override func becomeFirstResponder() -> Bool { let result = super.becomeFirstResponder() self.text = self.originalText self.textColor = self.originalTextColor return result } override func resignFirstResponder() -> Bool { let result = super.resignFirstResponder() updatePlaceHolder() return result } }


Use esta extensión, esta es la mejor manera de establecer un marcador de posición en UITextView. Pero asegúrese de haber adjuntado delegados a TextView. Puede configurar el marcador de posición de esta manera: -

func textViewDidChange(descriptionField: UITextView) { if descriptionField.text.isEmpty == false { descriptionPlaceholder.text = "" } else { descriptionPlaceholder.text = descriptionPlaceholderText } }


func setPlaceholder(){ var placeholderLabel = UILabel() placeholderLabel.text = "Describe your need..." placeholderLabel.font = UIFont.init(name: "Lato-Regular", size: 15.0) ?? UIFont.boldSystemFont(ofSize: 14.0) placeholderLabel.sizeToFit() descriptionTextView.addSubview(placeholderLabel) placeholderLabel.frame.origin = CGPoint(x: 5, y: (descriptionTextView.font?.pointSize)! / 2) placeholderLabel.textColor = UIColor.lightGray placeholderLabel.isHidden = !descriptionTextView.text.isEmpty } //Delegate Method. func textViewDidChange(_ textView: UITextView) { placeholderLabel.isHidden = !textView.text.isEmpty }


Swift 3.1

Esta extensión funcionó bien para mí: https://github.com/devxoul/UITextView-Placeholder

Aquí hay un fragmento de código:

Instalarlo a través de pod:

import UITextView_Placeholder

Importalo a tu clase

textView.placeholder = "Put some detail"

Y agregue placeholder propiedad a su ya creado UITextView

@IBDesignable class UIPlaceholderTextView: UITextView { var placeholderLabel: UILabel? override init(frame: CGRect, textContainer: NSTextContainer?) { super.init(frame: frame, textContainer: textContainer) sharedInit() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) sharedInit() } override func prepareForInterfaceBuilder() { sharedInit() } func sharedInit() { refreshPlaceholder() NotificationCenter.default.addObserver(self, selector: #selector(textChanged), name: .UITextViewTextDidChange, object: nil) } @IBInspectable var placeholder: String? { didSet { refreshPlaceholder() } } @IBInspectable var placeholderColor: UIColor? = .darkGray { didSet { refreshPlaceholder() } } @IBInspectable var placeholderFontSize: CGFloat = 14 { didSet { refreshPlaceholder() } } func refreshPlaceholder() { if placeholderLabel == nil { placeholderLabel = UILabel() let contentView = self.subviews.first ?? self contentView.addSubview(placeholderLabel!) placeholderLabel?.translatesAutoresizingMaskIntoConstraints = false placeholderLabel?.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: textContainerInset.left + 4).isActive = true placeholderLabel?.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: textContainerInset.right + 4).isActive = true placeholderLabel?.topAnchor.constraint(equalTo: contentView.topAnchor, constant: textContainerInset.top).isActive = true placeholderLabel?.bottomAnchor.constraint(lessThanOrEqualTo: contentView.bottomAnchor, constant: textContainerInset.bottom) } placeholderLabel?.text = placeholder placeholderLabel?.textColor = placeholderColor placeholderLabel?.font = UIFont.systemFont(ofSize: placeholderFontSize) } @objc func textChanged() { if self.placeholder?.isEmpty ?? true { return } UIView.animate(withDuration: 0.25) { if self.text.isEmpty { self.placeholderLabel?.alpha = 1.0 } else { self.placeholderLabel?.alpha = 0.0 } } } override var text: String! { didSet { textChanged() } } }

Eso es ... Así se ve (el tercer cuadro es a UITextView )


Actualizado para Swift 4

UITextView no tiene inherentemente una propiedad de marcador de posición, por lo que tendría que crear y manipular una mediante programación utilizando los métodos UITextViewDelegate . Recomiendo usar cualquiera de las soluciones # 1 o # 2 a continuación dependiendo del comportamiento deseado.

Nota: Para cualquier solución, agregue UITextViewDelegate a la clase y establezca textView.delegate = self para usar los métodos de delegado de la vista de texto.

Solución n. ° 1 : si desea que el marcador de posición desaparezca tan pronto como el usuario seleccione la vista de texto:

Primero configure UITextView para que contenga el texto de marcador de posición y UITextView en un color gris claro para imitar la apariencia del texto de marcador de posición de UITextField . Puede hacerlo en viewDidLoad o en la creación de la vista de texto.

textView.text = "Placeholder" textView.textColor = UIColor.lightGray

Luego, cuando el usuario comienza a editar la vista de texto, si la vista de texto contiene un marcador de posición (es decir, si su color de texto es gris claro), borre el texto del marcador de posición y configure el color del texto en negro para acomodar la entrada del usuario.

func textViewDidBeginEditing(_ textView: UITextView) { if textView.textColor == UIColor.lightGray { textView.text = nil textView.textColor = UIColor.black } }

Luego, cuando el usuario termina de editar la vista de texto y se resigna como el primer respondedor, si la vista de texto está vacía, restablezca su marcador de posición volviendo a agregar el texto del marcador de posición y configurando su color en gris claro.

func textViewDidEndEditing(_ textView: UITextView) { if textView.text.isEmpty { textView.text = "Placeholder" textView.textColor = UIColor.lightGray } }

Solución n. ° 2 : si desea que el marcador de posición se muestre siempre que la vista de texto esté vacía, incluso si la vista de texto está seleccionada:

Primero establezca el marcador de posición en viewDidLoad :

textView.text = "Placeholder" textView.textColor = UIColor.lightGray textView.becomeFirstResponder() textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)

(Nota: dado que el OP quería tener seleccionada la vista de texto tan pronto como se carga la vista, incorporé la selección de vista de texto en el código anterior. Si este no es su comportamiento deseado y no desea que la vista de texto se seleccione al cargar la vista, elimine las dos últimas líneas del fragmento de código anterior).

Luego utilice el método shouldChangeTextInRange UITextViewDelegate , así:

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { // Combine the textView text and the replacement text to // create the updated text string let currentText:String = textView.text let updatedText = (currentText as NSString).replacingCharacters(in: range, with: text) // If updated text view will be empty, add the placeholder // and set the cursor to the beginning of the text view if updatedText.isEmpty { textView.text = "Placeholder" textView.textColor = UIColor.lightGray textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument) } // Else if the text view''s placeholder is showing and the // length of the replacement string is greater than 0, set // the text color to black then set its text to the // replacement string else if textView.textColor == UIColor.lightGray && !text.isEmpty { textView.textColor = UIColor.black textView.text = text } // For every other case, the text should change with the usual // behavior... else { return true } // ...otherwise return false since the updates have already // been made return false }

Y también implemente textViewDidChangeSelection para evitar que el usuario cambie la posición del cursor mientras el marcador de posición es visible. (Nota: se llama a textViewDidChangeSelection antes de que se cargue la vista, así que solo verifique el color de la vista de texto si la ventana está visible):

func textViewDidChangeSelection(_ textView: UITextView) { if self.view.window != nil { if textView.textColor == UIColor.lightGray { textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument) } } }


Rápido:

Agregue su vista de texto mediante programación o mediante Interface Builder, si es el último, cree la salida:

@IBOutlet weak var yourTextView: UITextView!

Agregue el delegado (UITextViewDelegate):

class ViewController: UIViewController, UITextViewDelegate {

En el método viewDidLoad, agregue lo siguiente:

override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. yourTextView.delegate = self yourTextView.text = "Placeholder text goes right here..." yourTextView.textColor = UIColor.lightGray

Ahora permítanme presentarles la parte mágica, agregue esta función:

func textViewDidBeginEditing(_ textView: UITextView) { if yourTextView.textColor == UIColor.lightGray { yourTextView.text = "" yourTextView.textColor = UIColor.black } }

Tenga en cuenta que esto se ejecutará cada vez que comience la edición, allí verificaremos las condiciones para indicar el estado, utilizando la propiedad de color. Establecer texto a nil no lo recomiendo. Justo después de eso, configuramos el color del texto al deseado, en este caso, negro.

Ahora agregue esta función también:

func textViewDidEndEditing(_ textView: UITextView) { if yourTextView.text == "" { yourTextView.text = "Placeholder text ..." yourTextView.textColor = UIColor.lightGray } }

Permítanme insistir, no lo comparen con nada, ya lo he intentado y no funcionaría. Luego establecemos los valores de nuevo al estilo de marcador de posición, y establecemos el color de nuevo al color de marcador de posición porque es una condición para verificar textViewDidBeginEditing .


SET valor en vista carga

import UIKit protocol PlaceholderTextViewDelegate { func placeholderTextViewDidChangeText(_ text:String) func placeholderTextViewDidEndEditing(_ text:String) } final class PlaceholderTextView: UITextView { var notifier:PlaceholderTextViewDelegate? var placeholder: String? { didSet { placeholderLabel?.text = placeholder } } var placeholderColor = UIColor.lightGray var placeholderFont = UIFont.appMainFontForSize(14.0) { didSet { placeholderLabel?.font = placeholderFont } } fileprivate var placeholderLabel: UILabel? // MARK: - LifeCycle 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 NotificationCenter.default.addObserver(self, selector: #selector(PlaceholderTextView.textDidChangeHandler(notification:)), name: .UITextViewTextDidChange, object: nil) placeholderLabel = UILabel() placeholderLabel?.textColor = placeholderColor placeholderLabel?.text = placeholder placeholderLabel?.textAlignment = .left placeholderLabel?.numberOfLines = 0 } override func layoutSubviews() { super.layoutSubviews() placeholderLabel?.font = placeholderFont var height:CGFloat = placeholderFont.lineHeight if let data = placeholderLabel?.text { let expectedDefaultWidth:CGFloat = bounds.size.width let fontSize:CGFloat = placeholderFont.pointSize let textView = UITextView() textView.text = data textView.font = UIFont.appMainFontForSize(fontSize) let sizeForTextView = textView.sizeThatFits(CGSize(width: expectedDefaultWidth, height: CGFloat.greatestFiniteMagnitude)) let expectedTextViewHeight = sizeForTextView.height if expectedTextViewHeight > height { height = expectedTextViewHeight } } placeholderLabel?.frame = CGRect(x: 5, y: 0, width: bounds.size.width - 16, height: height) if text.isEmpty { addSubview(placeholderLabel!) bringSubview(toFront: placeholderLabel!) } else { placeholderLabel?.removeFromSuperview() } } func textDidChangeHandler(notification: Notification) { layoutSubviews() } } extension PlaceholderTextView : UITextViewDelegate { // MARK: - UITextViewDelegate func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { if(text == "/n") { textView.resignFirstResponder() return false } return true } func textViewDidChange(_ textView: UITextView) { notifier?.placeholderTextViewDidChangeText(textView.text) } func textViewDidEndEditing(_ textView: UITextView) { notifier?.placeholderTextViewDidEndEditing(textView.text) } }