UITextView es un componente de texto multilínea de UIKit, heredero de UIScrollView que admite la edición de texto atribuido con enlaces e imágenes incrustados. Según la documentación de Apple Developer (2025), UITextView proporciona UITextViewDelegate con callbacks textViewDidChange, shouldInteractWithURL y shouldInteractWithTextAttachment para el manejo de interacciones. A diferencia de UITextField, UITextView admite desplazamiento, estilos de texto mediante typingAttributes y dataDetectorTypes para la detección automática de enlaces, direcciones y fechas. Este es el componente principal para mostrar contenido e ingresar texto multilínea en aplicaciones iOS.
Puntos Clave
UITextView es un componente de UIKit diseñado para mostrar y editar texto multilínea. A diferencia de UILabel, UITextView admite selección de texto, edición, desplazamiento cuando el contenido supera el tamaño y texto atribuido. Al ser una subclase de UIScrollView, UITextView incluye automáticamente desplazamiento vertical y horizontal cuando el contenido se desborda — esto se configura mediante isScrollEnabled. La clase admite edición a través de la propiedad isEditable: establézcala en false para el modo de solo lectura. UITextView funciona con NSLayoutManager a través del sistema TextKit: NSTextStorage (almacenamiento de texto atribuido) → NSLayoutManager (diseño de líneas) → NSTextContainer (geometría del área de texto). Esta arquitectura permite diseños personalizados con ajuste de imágenes, texto multicolumna y diseños de texto complejos. UITextView se utiliza para mostrar artículos, descripciones, registros, comentarios y cualquier texto multilínea en iOS.
La diferencia entre UITextView y UITextField va mucho más allá del número de líneas. UITextField es un UIControl de una sola línea con soporte de placeholder, vistas izquierda/derecha y botón de borrado. UITextView es un UIScrollView multilínea con un sistema TextKit completo para texto atribuido. UITextField no admite NSAttributedString a nivel de visualización (solo mediante attributedText con limitaciones), UITextView maneja NSAttributedString completamente con diferentes fuentes, estilos de párrafo e imágenes incrustadas. UITextField tiene un botón de borrado incorporado (clearButtonMode), UITextView no — se requiere una implementación personalizada. UITextField se redimensiona automáticamente al contenido (intrinsicContentSize), UITextView requiere gestión manual de altura mediante observación de contentSize o restricciones de Auto Layout. UITextView admite dataDetectorTypes (detección automática de enlaces), UITextField lo admite desde iOS 16+. Para entrada de texto multilínea (comentarios, notas, mensajes) elija UITextView. Para campos de formulario (nombre, correo electrónico, contraseña) use UITextField.
| Característica | UITextView | UITextField |
|---|---|---|
| Líneas | Multilínea | Una línea |
| Placeholder | No (personalizado) | Incorporado |
| Atributos de texto | NSAttributedString completo | Limitado |
| Data Detectors | Soporte completo | iOS 16+ |
| Imágenes inline | Mediante NSTextAttachment | No compatible |
| Desplazamiento | Incorporado (UIScrollView) | No |
| Vista Izq./Der. | No | Incorporada |
NSAttributedString es una capacidad fundamental de UITextView que lo distingue de UITextField y UILabel. Una cadena atribuida permite establecer diferentes fuentes, colores, interlineado, alineación y enlaces dentro de un mismo texto. Propiedades: textView.attributedText = attributedString. Atributos clave de NSAttributedString.Key: font (.systemFont, .boldSystemFont, UIFont personalizado), foregroundColor, backgroundColor, paragraphStyle (NSMutableParagraphStyle con lineSpacing, alignment, lineBreakMode), link (URL para enlaces interactivos), underlineStyle, strikethroughStyle, shadow, baselineOffset, kern (espaciado entre letras). Para crear un attributedString use init(string:, attributes:) o NSMutableAttributedString para agregar atributos a diferentes rangos. UITextView muestra automáticamente los enlaces (atributo link) como interactivos — al presionarlos se activa el método delegado shouldInteractWithURL. Para restablecer atributos para nueva entrada use typingAttributes.
import UIKit
let textView = UITextView()
textView.isEditable = false
textView.isScrollEnabled = true
textView.dataDetectorTypes = [.link, .phoneNumber]
let attributedString = NSMutableAttributedString(
string: "Visit our website or call +1-800-555-0199"
)
attributedString.addAttributes([
.font: UIFont.systemFont(ofSize: 16),
.foregroundColor: UIColor.label,
], range: NSRange(location: 0, length: 11))
let linkRange = (attributedString.string as NSString)
.range(of: "website")
attributedString.addAttributes([
.link: URL(string: "https://example.com")!,
.foregroundColor: UIColor.systemBlue,
], range: linkRange)
textView.attributedText = attributedString
UITextViewDelegate es un protocolo que gestiona la edición y la interacción con el texto. Métodos principales: textViewDidBeginEditing(textView) — se llama cuando comienza la edición; textViewDidEndEditing — cuando termina la edición; textViewDidChange — en cada cambio de texto; textViewDidChangeSelection — cuando cambia la selección; textViewShouldInteractWithURL — cuando se pulsa un enlace (devuelve Bool, permite la transición); textViewShouldInteractWithTextAttachment — cuando se pulsa una imagen incrustada. Para manejar enlaces dentro de UITextView sobrescriba shouldInteractWithURL — en él puede: abrir URL en SFSafariViewController, mostrar UIAlertController para confirmación, manejar esquemas URL personalizados. Importante: si textView.isEditable = true, los enlaces no están disponibles para un solo toque — se requiere doble toque. Para enlaces interactivos en textView editable use gesture recognizers.
SFSafariViewController es la forma estándar de abrir enlaces en aplicaciones iOS. En el método shouldInteractWithURL cree SFSafariViewController con la URL y preséntelo modalmente o mediante navigationController. Para enlaces universales use UIApplication.shared.open(url, options) — pero esto sale de la aplicación. Para evitar la apertura de enlaces devuelva false en shouldInteractWithURL y maneje la URL usted mismo.
NSTextContainer es parte de la arquitectura TextKit, que define el área geométrica donde se muestra el texto de UITextView. Cada UITextView tiene un textContainer estándar, configurable mediante: textView.textContainerInset — márgenes del texto desde los bordes del textView (UIEdgeInsets); textView.textContainer.lineFragmentPadding — relleno horizontal dentro de cada línea; textView.textContainer.maximumNumberOfLines — límite de líneas (0 = sin límite); textView.textContainer.exclusionPaths — matriz de UIBezierPath para áreas que el texto debe rodear (imágenes, formas personalizadas). ExclusionPaths permiten diseños complejos: el texto rodea una imagen de perfil circular, un icono o cualquier forma arbitraria. Para altura dinámica de UITextView observe contentSize mediante KVO o delegado y actualice las restricciones.
// Dynamic UITextView height via contentSize
func textViewDidChange(textView: UITextView) {
let fixedWidth = textView.frame.size.width
let newSize = textView.sizeThatFits(
CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude)
)
heightConstraint.constant = newSize.height
UIView.animate(withDuration: 0.1) {
self.view.layoutIfNeeded()
}
}
// ExclusionPath for image wrapping
let imageFrame = CGRect(x: 16, y: 100, width: 80, height: 80)
let exclusionPath = UIBezierPath(rect: imageFrame)
textView.textContainer.exclusionPaths = [exclusionPath]
dataDetectorTypes es una propiedad de UITextView que reconoce automáticamente y hace interactivos ciertos tipos de datos en el texto: .link (URL, email), .phoneNumber (números de teléfono), .address (direcciones), .calendarEvent (fechas y eventos), .flightNumber (números de vuelo), .lookupSuggestion (sugerencias de búsqueda), .trackingNumber (números de seguimiento), .money (cantidades), .shipmentTrackingNumber, .all (todos los tipos). Data Detector funciona con NSDataDetector y URL, resaltando automáticamente los datos detectados. Para personalizar el manejo establezca dataDetectorTypes y sobrescriba shouldInteractWithURL en el delegado. Importante: dataDetectorTypes solo funciona para URL y phoneNumber sin configuración adicional — otros tipos pueden requerir iOS 16+. Data Detector no entra en conflicto con el atributo link en NSAttributedString — ambos mecanismos funcionan en paralelo. Para UITextView de solo lectura con contenido (noticias, artículos) establezca dataDetectorTypes = [.link, .phoneNumber].
Veamos dos ejemplos prácticos de uso de UITextView en aplicaciones iOS. El primero — una vista de texto de solo lectura con texto atribuido y detector de datos para mostrar contenido. El segundo — una vista de texto editable con placeholder perezoso y altura dinámica para un formulario de comentarios. Ambos ejemplos utilizan las mejores prácticas de UIKit: protocolo delegado, Auto Layout y TextKit.
El modo de solo lectura se activa estableciendo isEditable = false e isSelectable = true. Esto permite al usuario seleccionar texto y pulsar enlaces, pero no editarlo. Establezca dataDetectorTypes para la detección automática de enlaces, backgroundColor = .clear para fondo transparente. Para contenido largo use attributedText con NSMutableParagraphStyle lineSpacing para legibilidad. Agregue atributos link para enlaces clave dentro del texto.
import UIKit
class ArticleViewController: UIViewController {
let contentView = UITextView()
override func viewDidLoad() {
super.viewDidLoad()
contentView.isEditable = false
contentView.isSelectable = true
contentView.dataDetectorTypes = [.link, .phoneNumber]
contentView.backgroundColor = .clear
contentView.textContainerInset = UIEdgeInsets(
top: 8, left: 16,
bottom: 8, right: 16
)
contentView.delegate = self
loadArticleContent()
}
func loadArticleContent() {
guard let url = URL(string: "https://example.com/article")
else { return }
// Load content from URL and set attributedText
}
}
El Placeholder para UITextView no está incorporado — impleméntelo mediante un UILabel sobre el textView o mediante attributedText con verificación de isEmpty. Un enfoque simple: un UILabel con texto gris que se oculta cuando comienza la edición. En textViewDidChange verifique la presencia de texto y oculte/muestre el placeholder. Para una solución más elegante use la propiedad typingAttributes para establecer el color del texto de entrada. La altura dinámica del textView se logra observando contentSize y actualizando las restricciones — este es un patrón estándar para chats y formularios de comentarios.
Preguntas Frecuentes
UITextView no tiene un placeholder incorporado. La solución estándar: agregue un UILabel con texto gris sobre el textView. En textViewDidBeginEditing oculte la etiqueta, en textViewDidEndEditing muéstrela si el texto está vacío. Alternativamente: use attributedText con color gris como placeholder y restablézcalo cuando comience la edición. Para una solución lista para usar, use la biblioteca KMPlaceholderTextView o ReactorKit.
Establezca textContainerInset = .zero y lineFragmentPadding = 0: textView.textContainerInset = UIEdgeInsets.zero; textView.textContainer.lineFragmentPadding = 0. Adicionalmente: textView.contentInset = .zero. Esto eliminará por completo los márgenes desde los bordes del textView hasta el texto. Tenga en cuenta que lineFragmentPadding por defecto es 5.
Verifique: isSelectable = true (necesario para la interacción), dataDetectorTypes incluye .link, el delegado no devuelve false en shouldInteractWithURL. Si textView.isEditable = true, los enlaces no están disponibles para un solo toque — se requiere doble toque. Para enlaces interactivos en textView editable agregue UITapGestureRecognizer sobre el textView y maneje las URL manualmente.
Establezca isScrollEnabled = true y agregue una restricción de altura con un valor fijo. El texto que exceda la altura se desplazará. Para una UX óptima use maxHeight: observe contentSize y establezca la restricción de altura no superior a maxHeight. Cuando se exceda maxHeight active scrollEnabled. Este es un patrón estándar para campos de entrada de mensajes y comentarios.
Use NSTextAttachment: cree un objeto, establezca la imagen y los bounds, luego cree un NSAttributedString desde el attachment e insértelo en textView.attributedText. Ejemplo: let attachment = NSTextAttachment(); attachment.image = image; attachment.bounds = CGRect(x, y, width, height); let attributedString = NSAttributedString(attachment: attachment). La imagen se mostrará inline en el texto y se desplazará con él.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también