NSTextAttachment é uma classe do framework UIKit que permite incorporar imagens e outros objetos de mídia em texto formatado através do NSAttributedString. Ele funciona no nível do TextKit e Core Text, dando aos desenvolvedores controle sobre o tamanho, posição e comportamento dos anexos dentro do fluxo de texto. De acordo com a Apple Documentation (2025), o NSTextAttachment suporta imagens, PDF e contêineres de visualização personalizados, integrando-se com UITextView e UILabel. Compreender esta API é necessário para criar Rich Text em aplicativos iOS — desde chats e editores até feeds de notícias com ícones em legendas.
Pontos principais
NSTextAttachment é uma classe do framework UIKit que permite incorporar objetos de mídia diretamente no conteúdo de texto do NSAttributedString. Ao contrário de um UIImageView separado colocado ao lado do texto, o NSTextAttachment torna a imagem parte do fluxo de texto: a imagem se ajusta com as linhas, participa do alinhamento e ocupa espaço como um caractere comum.
A classe faz parte da arquitetura TextKit, que gerencia a renderização de texto no iOS e macOS. O TextKit divide o texto em glifos, leva em consideração kerning, ligaduras e entrelinha — e o NSTextAttachment se encaixa neste pipeline como um caractere especial que é renderizado não como uma letra, mas como um objeto gráfico.
Cada instância do NSTextAttachment contém contents (dados do arquivo), fileType (tipo de conteúdo UTI) e bounds (um retângulo em points que define tamanho e posição). De acordo com as Apple Human Interface Guidelines, bounds por padrão é o tamanho da imagem, mas pode ser alterado para um ajuste preciso com a fonte.
Use NSTextAttachment em vez de um UIImageView separado quando a imagem deve se comportar como parte do texto — em chats, feeds de notícias, editores de texto e formulários com ícones em campos de entrada.
O fluxo de trabalho básico com NSTextAttachment consiste em três etapas: criar uma instância, definir a imagem e anexá-la ao NSAttributedString. Vamos examinar o processo usando 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
Após chamar NSAttributedString(attachment:), o objeto NSTextAttachment é convertido para o atributo NSAttachmentAttributeName, que é anexado a um caractere especial de substituição de objeto (código 0xFFFC). Este caractere não é exibido como uma letra — em vez disso, a imagem da propriedade image é desenhada em seu lugar.
Se a imagem deve ser colocada no meio de uma linha de texto (por exemplo, um ícone após uma palavra), simplesmente insira o attachmentString na posição desejada no NSMutableAttributedString. O TextKit levará em conta automaticamente a altura da linha e alinhará a imagem à linha de base.
Importante: a propriedade image está disponível apenas no iOS (desde o iOS 7). No macOS, use a propriedade contents com NSImage. Para compatibilidade com versões anteriores, sempre prefira definir image diretamente em vez de confiar no contêiner de dados.
Por padrão, o NSTextAttachment exibe a imagem em seu tamanho original em points. Na prática, quase sempre é necessário ajustar o tamanho e a posição vertical — isso é feito usando a propriedade bounds.
A estrutura CGRect bounds inclui origin (deslocamento em X e Y) e size (largura e altura). O deslocamento em Y é particularmente importante: um valor negativo abaixa a imagem abaixo da linha de base, um valor positivo a eleva. Um cenário típico é alinhar um ícone ao centro de uma linha de texto.
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
)
O cálculo de alinhamento usa o capHeight da fonte — a altura de uma letra maiúscula, não a altura completa da linha. Isso garante que o ícone corresponda visualmente à borda superior do texto, em vez de flutuar entre a linha de base e o ascendente. O tamanho da imagem no exemplo é 18×18 pt, que é típico para ícones em texto de UI.
Se a imagem deve ser maior que a linha de texto (por exemplo, uma prévia de foto em um chat), o TextKit aumentará automaticamente o espaçamento entre linhas para a linha atual. Neste caso, bounds deve ser definido para o tamanho natural e o deslocamento em Y para zero.
NSTextAttachment suporta não apenas PNG e JPEG, mas também documentos PDF, bem como arquivos arbitrários através da propriedade contents. Isso o torna uma ferramenta universal para Rich Text em aplicativos iOS.
Ao definir uma imagem PDF em attachment.image, o sistema renderiza automaticamente a primeira página do documento. No entanto, para renderização precisa, use os dados diretamente através do inicializador com dados e tipo UTI:
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)
O parâmetro ofType aceita uma string UTI (Uniform Type Identifier). Os tipos padrão incluem: public.image (qualquer imagem), public.jpeg, public.png, com.adobe.pdf. Ao especificar a UTI correta, o sistema seleciona o método de renderização apropriado — para PDF é CGPDFDocument, para imagens é CGImageSource.
Para tipos de arquivo personalizados (por exemplo, gráficos vetoriais no formato SVG), você precisará de uma subclasse de NSTextAttachment que sobrescreva o método image(forBounds:textContainer:characterIndex:). Se a renderização padrão não for adequada, retorne nil e implemente o desenho através do Core Graphics no método draw.
NSTextAttachment funciona corretamente tanto em UILabel quanto em UITextView. No entanto, o UITextView oferece mais capacidades: interação com anexos (tocar em um ícone), edição de texto junto com imagens e suporte para NSAttachmentBehavior.
Para lidar com toques em NSTextAttachment no UITextView, use o protocolo UITextViewDelegate e o método textView(_:shouldInteractWith:in:interaction:). Este método é chamado quando o usuário toca em um anexo e permite navegar para uma tela, abrir um popup ou reproduzir uma animação.
func textView(_ textView: UITextView,
shouldInteractWith attachment: NSTextAttachment,
in characterRange: NSRange,
interaction: UITextItemInteraction) -> Bool {
if interaction == .preview {
return false
}
// Abrir tela de detalhes
showImageDetail(attachment.image)
return false
}
O método distingue tipos de interação através do parâmetro interaction: .preview (3D Touch / Haptic Touch), .default (toque normal) e .presentActions (menu de contexto). Para cada tipo, você pode definir seu próprio comportamento ou desativá-lo retornando false.
Ao editar UITextView com NSTextAttachment, é importante lembrar: excluir o caractere de substituição (0xFFFC) também exclui o anexo. O usuário vê a imagem como um único elemento — ela é selecionada como um todo, não pixel por pixel. Para suporte de arrastar e soltar anexos no iOS 15+, use NSTextAttachmentViewProvider.
O primeiro erro comum é ignorar bounds. Os desenvolvedores muitas vezes confiam no tamanho original da imagem, o que leva a ícones gigantes no texto ou, inversamente, imagens que são quase invisíveis. Sempre defina bounds explicitamente levando em consideração a fonte e o contexto.
O segundo erro é deslocamento Y incorreto. Um valor positivo em bounds.origin.y abaixa a imagem (no sistema de coordenadas do UIKit, o eixo Y aponta para baixo — isso parece contraintuitivo, mas é assim que o Core Graphics funciona). Para alinhar ao centro dentro de uma linha, use a fórmula com capHeight da fonte conforme mostrado na Seção 3.
O terceiro problema é perda de imagem ao mudar traitCollection. Quando o usuário alterna o Modo Escuro ou Dynamic Type, o tamanho da fonte pode mudar, mas bounds permanece o mesmo. A solução é calcular bounds dinamicamente no método layoutSubviews ou via KVO na fonte.
O quarto erro frequente é usar NSTextAttachment em UILabel com numberOfLines > 1. No modo multilinha com largura limitada, o TextKit quebra corretamente as linhas junto com a imagem. O problema surge quando a altura do anexo excede a altura da linha — as linhas adjacentes se sobrepõem. A solução é aumentar o lineSpacing através do NSMutableParagraphStyle.
Perguntas frequentes
NSTextAttachment torna a imagem parte do fluxo de texto: ela se ajusta, alinha e escala com o texto. UIImageView está vinculado às coordenadas da superview e não participa do layout do texto.
Sim, se você definir a propriedade attributedText em vez de text. UILabel exibe corretamente o NSTextAttachment, mas não suporta interatividade. Para toques no anexo, use UITextView.
Altere a propriedade bounds da instância existente do NSTextAttachment. O texto será automaticamente renderizado novamente com os novos tamanhos sem necessidade de criar um novo NSAttributedString.
NSTextAttachment suporta imagens estáticas. Para GIF e formatos animados, é necessária uma implementação personalizada através do NSTextAttachmentViewProvider no iOS 15+ ou através do CADisplayLink.
Crie uma instância de NSTextAttachment, defina a imagem ou dados, configure bounds, envolva em NSAttributedString(attachment:) e insira no NSMutableAttributedString usando o método insert(_:at:).
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também