NSTextAttachment: ce este și cum să adaugi o imagine în text pe iOS

Autor: IT Sectr Publicat: 2026-07-25 Timp de citire: 9 min

NSTextAttachment este o clasă din framework-ul UIKit care permite încorporarea imaginilor și a altor obiecte media în textul formatat prin NSAttributedString. Funcționează la nivelul TextKit și Core Text, oferind dezvoltatorilor control asupra dimensiunii, poziției și comportamentului atașamentelor în fluxul de text. Conform Apple Documentation (2025), NSTextAttachment suportă imagini, PDF și containere de vizualizare personalizate, integrându-se cu UITextView și UILabel. Înțelegerea acestui API este necesară pentru crearea de Rich Text în aplicațiile iOS — de la chat-uri și editori până la feed-uri de știri cu pictograme în subtitrări.

Puncte principale

  • NSTextAttachment — clasa UIKit pentru încorporarea media în textul formatat iOS.
  • Imaginea se adaugă prin NSAttributedString cu cheia NSAttachmentAttributeName.
  • Proprietatea bounds controlează dimensiunea și deplasarea verticală a atașamentului.
  • NSTextAttachment suportă imagini, PDF și fișiere personalizate prin container de date.
  • API se integrează cu UITextView, UILabel și TextKit pentru un layout flexibil al textului.

Ce este NSTextAttachment?

NSTextAttachment este o clasă din framework-ul UIKit care permite încorporarea obiectelor media direct în conținutul text al NSAttributedString. Spre deosebire de un UIImageView separat plasat lângă text, NSTextAttachment face ca imaginea să devină parte a fluxului de text: imaginea se deplasează împreună cu rândurile, participă la aliniere și ocupă spațiu ca un caracter obișnuit.

Clasa face parte din arhitectura TextKit, care gestionează redarea textului pe iOS și macOS. TextKit împarte textul în glife, ia în considerare kerning-ul, ligaturile și interlinia — iar NSTextAttachment se încorporează în această conductă ca un caracter special care se redează nu ca o literă, ci ca un obiect grafic.

Fiecare instanță NSTextAttachment conține proprietățile contents (datele fișierului), fileType (tipul UTI al conținutului) și bounds (dreptunghiul în points care definește dimensiunea și poziția). Conform Apple Human Interface Guidelines, bounds implicit este egal cu dimensiunea imaginii, dar poate fi modificat pentru o potrivire precisă la font.

Folosește NSTextAttachment în locul unui UIImageView separat atunci când imaginea trebuie să se comporte ca parte a textului — în chat-uri, feed-uri de știri, editori de text și formulare cu pictograme în câmpurile de introducere.

Cum să adaugi o imagine în text prin NSTextAttachment

Scenariul de bază de lucru cu NSTextAttachment constă în trei pași: crearea unei instanțe, setarea imaginii și atașarea la NSAttributedString. Să analizăm procesul pe exemplul 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

După apelarea NSAttributedString(attachment:), obiectul NSTextAttachment se transformă în atributul NSAttachmentAttributeName, care se atașează unui caracter de înlocuire special (object replacement character, codul 0xFFFC). Acest caracter nu se afișează ca o literă — în locul său se desenează imaginea din proprietatea image.

Dacă imaginea trebuie să se afle la mijlocul unui rând de text (de exemplu, o pictogramă după un cuvânt), inserează pur și simplu attachmentString în poziția dorită a NSMutableAttributedString. TextKit va lua automat în considerare înălțimea rândului și va alinia imaginea pe linia de bază.

Important: proprietatea image este disponibilă doar pe iOS (începând cu iOS 7). Pe macOS folosește proprietatea contents cu NSImage. Pentru compatibilitate inversă, setează întotdeauna image direct, nu te baza pe containerul de date.

Configurarea bounds și a poziției atașamentului

Implicit, NSTextAttachment afișează imaginea la dimensiunea sa originală în points. În practică, aproape întotdeauna este necesară ajustarea dimensiunii și poziției verticale — pentru aceasta se folosește proprietatea bounds.

Structura CGRect bounds include origin (deplasarea pe X și Y) și size (lățimea și înălțimea). Deplasarea pe Y este deosebit de importantă: o valoare negativă coboară imaginea sub linia de bază, una pozitivă o ridică. Un scenariu tipic — alinierea pictogramei la centrul rândului de text.

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
)

Calculul alinierii utilizează capHeight fontului — înălțimea literei mari, nu înălțimea completă a rândului. Aceasta garantează că pictograma se potrivește vizual cu marginea superioară a textului, nu plutește între baseline și ascender. Dimensiunea imaginii în exemplu este de 18×18 pt, ceea ce este tipic pentru pictogramele în textul UI.

Dacă imaginea trebuie să fie mai mare decât rândul de text (de exemplu, previzualizarea unei fotografii într-un chat), TextKit va mări automat spațiul dintre rânduri pentru rândul curent. În acest caz, bounds se setează la dimensiunea naturală, iar deplasarea pe Y este zero.

PDF și atașamente personalizate

NSTextAttachment suportă nu doar PNG și JPEG, ci și documente PDF, precum și fișiere arbitrare prin proprietatea contents. Acest lucru îl face un instrument universal pentru Rich Text în aplicațiile iOS.

La setarea unei imagini PDF în attachment.image, sistemul redă automat prima pagină a documentului. Totuși, pentru o afișare precisă, folosește datele direct prin inițializatorul cu data și tipul 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)

Parametrul ofType primește un șir UTI (Uniform Type Identifier). Tipurile standard: public.image (orice imagine), public.jpeg, public.png, com.adobe.pdf. La specificarea UTI corect, sistemul alege metoda de redare potrivită — pentru PDF este CGPDFDocument, pentru imagini — CGImageSource.

Pentru tipuri de fișiere personalizate (de exemplu, grafică vectorială în format SVG) va fi necesară o subclasă a NSTextAttachment care suprascrie metoda image(forBounds:textContainer:characterIndex:). Dacă redarea standard nu este potrivită, returnează nil și implementează desenarea prin Core Graphics în metoda draw.

NSTextAttachment în UITextView și delegare

NSTextAttachment funcționează corect atât în UILabel, cât și în UITextView. Cu toate acestea, UITextView oferă mai multe posibilități: interacțiunea cu atașamentele (atingerea pictogramei), editarea textului împreună cu imaginile și suportul pentru NSAttachmentBehavior.

Pentru gestionarea atingerii NSTextAttachment în UITextView se folosește delegatul UITextViewDelegate și metoda textView(_:shouldInteractWith:in:interaction:). Această metodă este apelată atunci când utilizatorul atinge atașamentul și permite navigarea la un ecran, deschiderea unui pop-up sau redarea unei animații.

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

Metoda diferențiază tipurile de interacțiune prin parametrul interaction: .preview (3D Touch / Haptic Touch), .default (atingere obișnuită) și .presentActions (meniu contextual). Pentru fiecare tip poți seta propriul comportament sau îl poți interzice, returnând false.

La editarea UITextView cu NSTextAttachment este important de reținut: ștergerea caracterului de înlocuire (0xFFFC) șterge și atașamentul. Utilizatorul vede imaginea ca un element unitar — aceasta se selectează în întregime, nu pixel cu pixel. Pentru suportul de glisare a atașamentelor în iOS 15+, folosește NSTextAttachmentViewProvider.

Erori tipice la lucrul cu NSTextAttachment

Prima eroare frecventă — ignorarea bounds. Dezvoltatorii se bazează adesea pe dimensiunea originală a imaginii, ceea ce duce la pictograme gigantice în text sau, dimpotrivă, la imagini abia vizibile. Setează întotdeauna bounds explicit, ținând cont de font și context.

A doua eroare — deplasarea incorectă pe Y. O valoare pozitivă în bounds.origin.y coboară imaginea (în sistemul de coordonate UIKit, axa Y este orientată în jos — pare ilogic, dar așa funcționează Core Graphics). Pentru alinierea la centrul rândului, folosește formula cu capHeight fontului, așa cum este arătat în secțiunea 3.

A treia problemă — pierderea imaginii la schimbarea traitCollection. Când utilizatorul comută Dark Mode sau Dynamic Type, dimensiunea fontului se poate modifica, iar bounds rămâne același. Soluția — calculează bounds dinamic în metoda layoutSubviews sau prin KVO pe font.

A patra eroare frecventă — utilizarea NSTextAttachment în UILabel cu numberOfLines > 1. În modul multi-rând și lățime limitată, TextKit transferă corect rândurile împreună cu imaginea. Problema apare când înălțimea atașamentului depășește înălțimea rândului — rândurile vecine se suprapun. Soluția — mărește lineSpacing prin NSMutableParagraphStyle.

Întrebări frecvente

Cu ce se deosebește NSTextAttachment de UIImageView în text?

NSTextAttachment face imaginea parte a fluxului de text: se deplasează, se aliniază și se scalează împreună cu textul. UIImageView este legat de coordonatele superview-ului și nu participă la layout-ul textului.

Se poate adăuga NSTextAttachment în UILabel?

Da, dacă setezi proprietatea attributedText în loc de text. UILabel afișează corect NSTextAttachment, dar nu suportă interactivitate. Pentru atingerea atașamentelor folosește UITextView.

Cum se modifică dimensiunea imaginii după crearea attachment-ului?

Modifică proprietatea bounds a instanței existente de NSTextAttachment. Textul se va reranda automat cu noile dimensiuni, fără a fi nevoie să creezi un nou NSAttributedString.

Suportă NSTextAttachment imagini animate?

NSTextAttachment suportă imagini statice. Pentru GIF și formate animate este necesară o implementare personalizată prin NSTextAttachmentViewProvider în iOS 15+ sau prin CADisplayLink.

Cum se adaugă NSTextAttachment în text programatic?

Creează o instanță NSTextAttachment, setează image sau data, configurează bounds, înfășoară în NSAttributedString(attachment:) și inserează în NSMutableAttributedString prin metoda insert(_:at:).

Concluzii

  • NSTextAttachment — clasa UIKit pentru încorporarea imaginilor, PDF-urilor și altor medii în textul formatat.
  • Imaginea se adaugă prin NSAttributedString(attachment:) și devine parte a fluxului de text.
  • Proprietatea bounds controlează dimensiunea și poziția: seteaz-o întotdeauna explicit ținând cont de font.
  • Pentru alinierea pictogramei la centrul rândului folosește formula cu capHeight fontului curent.
  • Atașamentele PDF sunt suportate prin inițializatorul cu data și tipul UTI corect.
  • Pentru gestionarea atingerii atașamentului folosește UITextViewDelegate și metoda shouldInteractWith.
  • La schimbarea Dynamic Type recalculează bounds dinamic pentru a evita suprapunerea rândurilor.

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și