NSTextAttachment est une classe du framework UIKit permettant d’intégrer des images et d’autres objets médias dans du texte formaté via NSAttributedString. Il fonctionne au niveau de TextKit et Core Text, donnant aux développeurs le contrôle sur la taille, la position et le comportement des pièces jointes dans le flux de texte. Selon Apple Documentation (2025), NSTextAttachment prend en charge les images, PDF et conteneurs de vue personnalisés, en s’intégrant avec UITextView et UILabel. Comprendre cette API est nécessaire pour créer du Rich Text dans les applications iOS — des chats et éditeurs aux flux d’actualités avec des icônes dans les légendes.
Points clés
NSTextAttachment est une classe du framework UIKit qui permet d’intégrer des objets médias directement dans le contenu textuel de NSAttributedString. Contrairement à un UIImageView séparé placé à côté du texte, NSTextAttachment fait partie intégrante du flux de texte : l’image suit le retour à la ligne, participe à l’alignement et occupe de l’espace comme un caractère normal.
Cette classe fait partie de l’architecture TextKit, qui gère le rendu du texte sur iOS et macOS. TextKit décompose le texte en glyphes, prend en compte le crénage, les ligatures et l’interlignage — et NSTextAttachment s’insère dans ce pipeline comme un caractère spécial qui s’affiche non pas comme une lettre mais comme un objet graphique.
Chaque instance de NSTextAttachment contient contents (données du fichier), fileType (type de contenu UTI) et bounds (un rectangle en points définissant la taille et la position). Selon les Apple Human Interface Guidelines, bounds est par défaut la taille de l’image, mais peut être modifié pour un ajustement précis avec la police.
Utilisez NSTextAttachment au lieu d’un UIImageView séparé lorsque l’image doit se comporter comme faisant partie du texte — dans les chats, les fils d’actualité, les éditeurs de texte et les formulaires avec des icônes dans les champs de saisie.
Le flux de travail de base avec NSTextAttachment comprend trois étapes : créer une instance, définir l’image et l’attacher à NSAttributedString. Examinons le processus en utilisant 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
Après avoir appelé NSAttributedString(attachment:), l’objet NSTextAttachment est converti en attribut NSAttachmentAttributeName, qui est attaché à un caractère spécial de remplacement d’objet (code 0xFFFC). Ce caractère ne s’affiche pas comme une lettre — à la place, l’image de la propriété image est dessinée à sa place.
Si l’image doit être placée au milieu d’une ligne de texte (par exemple, une icône après un mot), insérez simplement attachmentString à la position souhaitée dans NSMutableAttributedString. TextKit prendra automatiquement en compte la hauteur de ligne et alignera l’image sur la ligne de base.
Important : la propriété image est disponible uniquement sur iOS (depuis iOS 7). Sur macOS, utilisez la propriété contents avec NSImage. Pour la compatibilité ascendante, préférez toujours définir image directement plutôt que de vous fier au conteneur de données.
Par défaut, NSTextAttachment affiche l’image à sa taille d’origine en points. En pratique, il est presque toujours nécessaire d’ajuster la taille et la position verticale — cela se fait via la propriété bounds.
La structure CGRect bounds comprend origin (décalage en X et Y) et size (largeur et hauteur). Le décalage en Y est particulièrement important : une valeur négative abaisse l’image sous la ligne de base, une valeur positive la remonte. Un scénario typique consiste à aligner une icône au centre d’une ligne de texte.
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
)
Le calcul d’alignement utilise la capHeight de la police — la hauteur d’une lettre majuscule, pas la hauteur totale de la ligne. Cela garantit que l’icône correspond visuellement au bord supérieur du texte plutôt que de flotter entre la ligne de base et le jambage supérieur. La taille de l’image dans l’exemple est de 18×18 pt, ce qui est typique pour les icônes dans le texte d’interface.
Si l’image doit être plus grande que la ligne de texte (par exemple, un aperçu de photo dans un chat), TextKit augmentera automatiquement l’interlignage pour la ligne actuelle. Dans ce cas, bounds doit être défini à la taille naturelle et le décalage en Y à zéro.
NSTextAttachment prend en charge non seulement PNG et JPEG, mais aussi les documents PDF, ainsi que des fichiers arbitraires via la propriété contents. Cela en fait un outil universel pour le Rich Text dans les applications iOS.
Lors de la définition d’une image PDF dans attachment.image, le système rend automatiquement la première page du document. Cependant, pour un rendu précis, utilisez les données directement via l’initialiseur avec des données et un type 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)
Le paramètre ofType accepte une chaîne UTI (Uniform Type Identifier). Les types standard incluent : public.image (toute image), public.jpeg, public.png, com.adobe.pdf. En spécifiant l’UTI correcte, le système sélectionne la méthode de rendu appropriée — pour PDF c’est CGPDFDocument, pour les images c’est CGImageSource.
Pour les types de fichiers personnalisés (par exemple, les graphiques vectoriels au format SVG), vous aurez besoin d’une sous-classe de NSTextAttachment qui remplace la méthode image(forBounds:textContainer:characterIndex:). Si le rendu standard ne convient pas, retournez nil et implémentez le dessin via Core Graphics dans la méthode draw.
NSTextAttachment fonctionne correctement à la fois dans UILabel et UITextView. Cependant, UITextView offre plus de possibilités : interaction avec les pièces jointes (tap sur une icône), édition de texte avec des images et prise en charge de NSAttachmentBehavior.
Pour gérer les taps sur NSTextAttachment dans UITextView, utilisez le protocole UITextViewDelegate et la méthode textView(_:shouldInteractWith:in:interaction:). Cette méthode est appelée lorsque l’utilisateur tape sur une pièce jointe et permet de naviguer vers un écran, d’ouvrir une popup ou de lancer une animation.
func textView(_ textView: UITextView,
shouldInteractWith attachment: NSTextAttachment,
in characterRange: NSRange,
interaction: UITextItemInteraction) -> Bool {
if interaction == .preview {
return false
}
// Ouvrir l’écran de détails
showImageDetail(attachment.image)
return false
}
La méthode distingue les types d’interaction via le paramètre interaction : .preview (3D Touch / Haptic Touch), .default (tap normal) et .presentActions (menu contextuel). Pour chaque type, vous pouvez définir votre propre comportement ou le désactiver en retournant false.
Lors de l’édition d’UITextView avec NSTextAttachment, il est important de se rappeler : supprimer le caractère de remplacement (0xFFFC) supprime également la pièce jointe. L’utilisateur voit l’image comme un élément unique — elle est sélectionnée dans son ensemble, pas pixel par pixel. Pour la prise en charge du glisser-déposer des pièces jointes sur iOS 15+, utilisez NSTextAttachmentViewProvider.
La première erreur courante est d’ignorer bounds. Les développeurs se fient souvent à la taille d’image d’origine, ce qui conduit à des icônes géantes dans le texte ou, à l’inverse, à des images à peine visibles. Définissez toujours bounds explicitement en tenant compte de la police et du contexte.
La deuxième erreur est un décalage Y incorrect. Une valeur positive dans bounds.origin.y abaisse l’image (dans le système de coordonnées d’UIKit, l’axe Y pointe vers le bas — cela semble contre-intuitif, mais c’est ainsi que fonctionne Core Graphics). Pour aligner au centre d’une ligne, utilisez la formule avec la capHeight de la police comme indiqué dans la Section 3.
Le troisième problème est la perte d’image lors du changement de traitCollection. Lorsque l’utilisateur passe en mode sombre ou Dynamic Type, la taille de la police peut changer, mais bounds reste identique. La solution consiste à calculer bounds dynamiquement dans la méthode layoutSubviews ou via KVO sur la police.
La quatrième erreur fréquente est l’utilisation de NSTextAttachment dans UILabel avec numberOfLines > 1. En mode multiligne avec une largeur limitée, TextKit gère correctement le retour à la ligne avec l’image. Le problème survient lorsque la hauteur de la pièce jointe dépasse la hauteur de ligne — les lignes adjacentes se chevauchent. La solution consiste à augmenter lineSpacing via NSMutableParagraphStyle.
Foire aux questions
NSTextAttachment fait partie intégrante du flux de texte : il suit le retour à la ligne, s’aligne et se met à l’échelle avec le texte. UIImageView est lié aux coordonnées de la superview et ne participe pas à la mise en page du texte.
Oui, si vous définissez la propriété attributedText au lieu de text. UILabel affiche correctement NSTextAttachment mais ne prend pas en charge l’interactivité. Pour les taps sur la pièce jointe, utilisez UITextView.
Modifiez la propriété bounds de l’instance existante de NSTextAttachment. Le texte sera automatiquement rendu avec les nouvelles tailles sans avoir besoin de créer un nouveau NSAttributedString.
NSTextAttachment prend en charge les images statiques. Pour les GIF et les formats animés, une implémentation personnalisée via NSTextAttachmentViewProvider sur iOS 15+ ou via CADisplayLink est nécessaire.
Créez une instance de NSTextAttachment, définissez l’image ou les données, configurez bounds, enveloppez-le dans NSAttributedString(attachment:) et insérez-le dans NSMutableAttributedString via la méthode insert(_:at:).
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi