NSTextAttachment: qué es y cómo agregar una imagen al texto en iOS

Autor: IT Sectr Publicado: 2026-07-25 Tiempo de lectura: 9 min

NSTextAttachment es una clase del framework UIKit que permite incrustar imágenes y otros objetos multimedia en texto formateado a través de NSAttributedString. Funciona a nivel de TextKit y Core Text, dando a los desarrolladores control sobre el tamaño, la posición y el comportamiento de los attachments dentro del flujo de texto. Según Apple Documentation (2025), NSTextAttachment admite imágenes, PDF y contenedores de vista personalizados, integrándose con UITextView y UILabel. Comprender esta API es necesario para crear Rich Text en aplicaciones iOS, desde chats y editores hasta feeds de noticias con iconos en los pies de foto.

Puntos clave

  • NSTextAttachment es una clase de UIKit para incrustar medios en texto formateado de iOS.
  • Se agrega una imagen a través de NSAttributedString con la clave NSAttachmentAttributeName.
  • La propiedad bounds controla el tamaño y el desplazamiento vertical del attachment.
  • NSTextAttachment admite imágenes, PDF y archivos personalizados a través de un contenedor de datos.
  • La API se integra con UITextView, UILabel y TextKit para un diseño de texto flexible.

¿Qué es NSTextAttachment?

NSTextAttachment es una clase del framework UIKit que permite incrustar objetos multimedia directamente en el contenido de texto de NSAttributedString. A diferencia de un UIImageView separado colocado junto al texto, NSTextAttachment hace que la imagen sea parte del flujo de texto: la imagen se ajusta con las líneas, participa en la alineación y ocupa espacio como un carácter normal.

La clase es parte de la arquitectura TextKit, que gestiona la representación del texto en iOS y macOS. TextKit divide el texto en glifos, tiene en cuenta el kerning, las ligaduras y el interlineado, y NSTextAttachment se integra en este pipeline como un carácter especial que se renderiza no como una letra sino como un objeto gráfico.

Cada instancia de NSTextAttachment contiene contents (datos del archivo), fileType (tipo de contenido UTI) y bounds (un rectángulo en points que define el tamaño y la posición). Según Apple Human Interface Guidelines, bounds por defecto es el tamaño de la imagen, pero se puede cambiar para un ajuste preciso con la fuente.

Use NSTextAttachment en lugar de un UIImageView separado cuando la imagen deba comportarse como parte del texto, en chats, feeds de noticias, editores de texto y formularios con iconos en campos de entrada.

Cómo agregar una imagen al texto mediante NSTextAttachment

El flujo de trabajo básico con NSTextAttachment consta de tres pasos: crear una instancia, establecer la imagen y adjuntarla a NSAttributedString. Veamos el proceso usando Swift.

swift
let attachment = NSTextAttachment()
attachment.image = UIImage(named: "icon-star")

let attachmentString = NSAttributedString(attachment: attachment)

let text = NSMutableAttributedString(string: "Rating: ")
text.append(attachmentString)

let label = UILabel()
label.attributedText = text

Después de llamar a NSAttributedString(attachment:), el objeto NSTextAttachment se convierte en el atributo NSAttachmentAttributeName, que se adjunta a un carácter especial de reemplazo de objeto (código 0xFFFC). Este carácter no se muestra como una letra; en su lugar, se dibuja la imagen de la propiedad image.

Si la imagen debe colocarse en medio de una línea de texto (por ejemplo, un icono después de una palabra), simplemente inserte attachmentString en la posición deseada en NSMutableAttributedString. TextKit tendrá en cuenta automáticamente la altura de la línea y alineará la imagen con la línea base.

Importante: la propiedad image solo está disponible en iOS (desde iOS 7). En macOS, use la propiedad contents con NSImage. Para compatibilidad con versiones anteriores, siempre prefiera establecer image directamente en lugar de depender del contenedor de datos.

Configuración de bounds y posición del attachment

Por defecto, NSTextAttachment muestra la imagen en su tamaño original en points. En la práctica, casi siempre es necesario ajustar el tamaño y la posición vertical, lo que se hace mediante la propiedad bounds.

La estructura CGRect bounds incluye origin (desplazamiento en X e Y) y size (ancho y alto). El desplazamiento en Y es particularmente importante: un valor negativo baja la imagen por debajo de la línea base, un valor positivo la sube. Un escenario típico es alinear un icono al centro de una línea de texto.

swift
let attachment = NSTextAttachment()
attachment.image = UIImage(named: "icon-star")

let font = UIFont.systemFont(ofSize: 16)
let fontCapHeight = font.capHeight
let imageSize = CGSize(width: 18, height: 18)

attachment.bounds = CGRect(
    x: 0,
    y: (fontCapHeight - imageSize.height) / 2,
    width: imageSize.width,
    height: imageSize.height
)

El cálculo de alineación utiliza el capHeight de la fuente, la altura de una letra mayúscula, no la altura completa de la línea. Esto garantiza que el icono coincida visualmente con el borde superior del texto en lugar de flotar entre la línea base y el ascendente. El tamaño de la imagen en el ejemplo es de 18×18 pt, que es típico para iconos en texto de UI.

Si la imagen debe ser más grande que la línea de texto (por ejemplo, una vista previa de foto en un chat), TextKit aumentará automáticamente el interlineado para la línea actual. En este caso, bounds debe establecerse al tamaño natural y el desplazamiento en Y a cero.

PDF y attachments personalizados

NSTextAttachment admite no solo PNG y JPEG, sino también documentos PDF, así como archivos arbitrarios a través de la propiedad contents. Esto lo convierte en una herramienta universal para Rich Text en aplicaciones iOS.

Al establecer una imagen PDF en attachment.image, el sistema renderiza automáticamente la primera página del documento. Sin embargo, para una representación precisa, use los datos directamente a través del inicializador con datos y tipo UTI:

swift
guard let pdfData = Bundle.main.url(forResource: "document",
                                  withExtension: "pdf") else { return }

let fileData = Data(contentsOf: pdfData)
let attachment = NSTextAttachment(data: fileData,
                                       ofType: "com.adobe.pdf")

attachment.bounds = CGRect(x: 0, y: -4,
                           width: 24, height: 24)

let pdfString = NSAttributedString(attachment: attachment)

El parámetro ofType acepta una cadena UTI (Uniform Type Identifier). Los tipos estándar incluyen: public.image (cualquier imagen), public.jpeg, public.png, com.adobe.pdf. Al especificar la UTI correcta, el sistema selecciona el método de renderizado apropiado: para PDF es CGPDFDocument, para imágenes es CGImageSource.

Para tipos de archivo personalizados (por ejemplo, gráficos vectoriales en formato SVG), necesitará una subclase de NSTextAttachment que sobrescriba el método image(forBounds:textContainer:characterIndex:). Si la representación estándar no es adecuada, devuelva nil e implemente el dibujo a través de Core Graphics en el método draw.

NSTextAttachment en UITextView y delegación

NSTextAttachment funciona correctamente tanto en UILabel como en UITextView. Sin embargo, UITextView proporciona más capacidades: interacción con attachments (tocar un icono), edición de texto junto con imágenes y soporte para NSAttachmentBehavior.

Para manejar toques en NSTextAttachment en UITextView, use el protocolo UITextViewDelegate y el método textView(_:shouldInteractWith:in:interaction:). Este método se llama cuando el usuario toca un attachment y permite navegar a una pantalla, abrir un popup o reproducir una animación.

swift
func textView(_ textView: UITextView,
                shouldInteractWith attachment: NSTextAttachment,
                in characterRange: NSRange,
                interaction: UITextItemInteraction) -> Bool {
    if interaction == .preview {
        return false
    }
    // Abrir pantalla de detalles
    showImageDetail(attachment.image)
    return false
}

El método distingue los tipos de interacción a través del parámetro interaction: .preview (3D Touch / Haptic Touch), .default (toque normal) y .presentActions (menú contextual). Para cada tipo, puede definir su propio comportamiento o deshabilitarlo devolviendo false.

Al editar UITextView con NSTextAttachment, es importante recordar: eliminar el carácter de reemplazo (0xFFFC) también elimina el attachment. El usuario ve la imagen como un solo elemento: se selecciona en su conjunto, no píxel por píxel. Para soporte de arrastrar y soltar attachments en iOS 15+, use NSTextAttachmentViewProvider.

Errores comunes al trabajar con NSTextAttachment

El primer error común es ignorar bounds. Los desarrolladores a menudo confían en el tamaño original de la imagen, lo que lleva a iconos gigantes en el texto o, por el contrario, a imágenes que apenas se ven. Siempre establezca bounds explícitamente teniendo en cuenta la fuente y el contexto.

El segundo error es desplazamiento incorrecto en Y. Un valor positivo en bounds.origin.y baja la imagen (en el sistema de coordenadas de UIKit, el eje Y apunta hacia abajo, lo que parece contradictorio, pero así funciona Core Graphics). Para alinear al centro dentro de una línea, use la fórmula con capHeight de la fuente como se muestra en la Sección 3.

El tercer problema es pérdida de imagen al cambiar traitCollection. Cuando el usuario cambia el Modo Oscuro o Dynamic Type, el tamaño de la fuente puede cambiar, pero bounds permanece igual. La solución es calcular bounds dinámicamente en el método layoutSubviews o mediante KVO en font.

El cuarto error frecuente es usar NSTextAttachment en UILabel con numberOfLines > 1. En modo multilínea con ancho limitado, TextKit ajusta correctamente las líneas junto con la imagen. El problema surge cuando la altura del attachment supera la altura de la línea: las líneas adyacentes se superponen. La solución es aumentar lineSpacing mediante NSMutableParagraphStyle.

Preguntas frecuentes

¿En qué se diferencia NSTextAttachment de UIImageView en el texto?

NSTextAttachment hace que la imagen sea parte del flujo de texto: se ajusta, alinea y escala con el texto. UIImageView está vinculado a las coordenadas de la superview y no participa en el diseño del texto.

¿Se puede agregar NSTextAttachment a UILabel?

Sí, si se establece la propiedad attributedText en lugar de text. UILabel muestra correctamente NSTextAttachment pero no admite interactividad. Para toques en el attachment, use UITextView.

¿Cómo cambiar el tamaño de la imagen después de crear el attachment?

Cambie la propiedad bounds de la instancia existente de NSTextAttachment. El texto se volverá a renderizar automáticamente con los nuevos tamaños sin necesidad de crear un nuevo NSAttributedString.

¿NSTextAttachment admite imágenes animadas?

NSTextAttachment admite imágenes estáticas. Para GIF y formatos animados, se requiere una implementación personalizada mediante NSTextAttachmentViewProvider en iOS 15+ o mediante CADisplayLink.

¿Cómo agregar NSTextAttachment al texto mediante programación?

Cree una instancia de NSTextAttachment, establezca la imagen o los datos, configure bounds, envuélvalo en NSAttributedString(attachment:) e insértelo en NSMutableAttributedString usando el método insert(_:at:).

Resumen

  • NSTextAttachment es una clase de UIKit para incrustar imágenes, PDF y otros medios en texto formateado.
  • Se agrega una imagen mediante NSAttributedString(attachment:) y se convierte en parte del flujo de texto.
  • La propiedad bounds controla el tamaño y la posición: siempre establézcala explícitamente considerando la fuente.
  • Para centrar un icono dentro de una línea, use la fórmula con el capHeight de la fuente actual.
  • Los attachments PDF son compatibles mediante el inicializador con data y el tipo UTI correcto.
  • Para manejar toques en attachments, use UITextViewDelegate y el método shouldInteractWith.
  • Cuando Dynamic Type cambie, recalcule bounds dinámicamente para evitar la superposición de líneas.

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.

Discutir el proyecto

Lea también