NSTextAttachment: что это и как добавить картинку в текст на iOS

Автор: IT Sectr Опубликовано: 2026-07-25 Время чтения: 9 мин

NSTextAttachment — это класс из фреймворка UIKit, позволяющий встраивать изображения и другие медиа-объекты в форматированный текст через NSAttributedString. Он работает на уровне TextKit и Core Text, давая разработчикам контроль над размером, позицией и поведением вложений внутри текстового потока. По данным Apple Documentation (2025), NSTextAttachment поддерживает изображения, PDF и кастомные вью-контейнеры, интегрируясь с UITextView и UILabel. Понимание этого API необходимо для создания Rich Text в iOS-приложениях — от чатов и редакторов до лент новостей с иконками в подписях.

Главное

  • NSTextAttachment — класс UIKit для встраивания медиа в форматированный текст iOS.
  • Изображение добавляется через NSAttributedString с ключом NSAttachmentAttributeName.
  • Свойство bounds управляет размером и вертикальным смещением вложения.
  • NSTextAttachment поддерживает изображения, PDF и кастомные файлы через data-контейнер.
  • API интегрируется с UITextView, UILabel и TextKit для гибкой вёрстки текста.

Что такое NSTextAttachment?

NSTextAttachment — это класс из фреймворка UIKit, который позволяет встраивать медиа-объекты непосредственно в текстовое содержимое NSAttributedString. В отличие от отдельного UIImageView, расположенного рядом с текстом, NSTextAttachment делает изображение частью текстового потока: картинка переносится вместе со строками, участвует в выравнивании и занимает место как обычный символ.

Класс является частью архитектуры TextKit, которая управляет отрисовкой текста на iOS и macOS. TextKit разбивает текст на глифы, учитывает кернинг, лигатуры и интерлиньяж — и NSTextAttachment встраивается в этот конвейер как специальный символ, который рендерится не как буква, а как графический объект.

Каждый экземпляр NSTextAttachment содержит свойство contents (данные файла), fileType (UTI-тип контента) и bounds (прямоугольник в points, определяющий размер и положение). По данным Apple Human Interface Guidelines, bounds по умолчанию равен размеру изображения, но может быть изменён для точной подгонки под шрифт.

Используйте NSTextAttachment вместо отдельного UIImageView, когда изображение должно вести себя как часть текста — в чатах, новостных лентах, текстовых редакторах и формах с иконками в полях ввода.

Как добавить изображение в текст через NSTextAttachment

Базовый сценарий работы с NSTextAttachment состоит из трёх шагов: создать экземпляр, задать изображение и прикрепить к NSAttributedString. Рассмотрим процесс на примере 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

После вызова NSAttributedString(attachment:) объект NSTextAttachment преобразуется в атрибут NSAttachmentAttributeName, который прикрепляется к специальному символу-заменителю (object replacement character, код 0xFFFC). Этот символ не отображается как буква — вместо него рисуется изображение из свойства image.

Если изображение должно располагаться в середине строки текста (например, иконка после слова), просто вставьте attachmentString в нужную позицию NSMutableAttributedString. TextKit автоматически учтёт высоту строки и выровняет картинку по базовой линии.

Важно: свойство image доступно только на iOS (начиная с iOS 7). На macOS используйте свойство contents с NSImage. Для обратной совместимости preferred всегда устанавливать image напрямую, а не полагаться на data-контейнер.

Настройка bounds и позиции вложения

По умолчанию NSTextAttachment отображает изображение в его оригинальном размере в points. На практике почти всегда требуется скорректировать размер и вертикальное положение — для этого используется свойство bounds.

Структура CGRect bounds включает origin (смещение по X и Y) и size (ширина и высота). Смещение по Y особенно важно: отрицательное значение опускает картинку ниже базовой линии, положительное — поднимает. Типичный сценарий — выровнять иконку по центру строки текста.

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
)

Расчёт выравнивания использует capHeight шрифта — высоту заглавной буквы, а не полную высоту строки. Это гарантирует, что иконка визуально совпадает с верхней границей текста, а не болтается между baseline и ascender. Размер изображения в примере — 18×18 pt, что типично для иконок в UI-тексте.

Если изображение должно быть больше строки текста (например, превью фотографии в чате), TextKit автоматически увеличит межстрочный интервал для текущей строки. В этом случае bounds задаётся в натуральную величину, а смещение по Y — zero.

PDF и кастомные вложения

NSTextAttachment поддерживает не только PNG и JPEG, но и PDF-документы, а также произвольные файлы через свойство contents. Это делает его универсальным инструментом для Rich Text в iOS-приложениях.

При установке PDF-изображения в attachment.image система автоматически рендерит первую страницу документа. Однако для точного отображения используйте данные напрямую через инициализатор с data и 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)

Параметр ofType принимает UTI-строку (Uniform Type Identifier). Стандартные типы: public.image (любое изображение), public.jpeg, public.png, com.adobe.pdf. При указании корректного UTI система выбирает правильный способ рендеринга — для PDF это CGPDFDocument, для изображений — CGImageSource.

Для кастомных типов файлов (например, векторная графика в формате SVG) потребуется подкласс NSTextAttachment, переопределяющий метод image(forBounds:textContainer:characterIndex:). Если стандартная отрисовка не подходит, верните nil и реализуйте рисование через Core Graphics в методе draw.

NSTextAttachment в UITextView и делегирование

NSTextAttachment корректно работает как в UILabel, так и в UITextView. Однако UITextView предоставляет больше возможностей: взаимодействие с вложениями (тап по иконке), редактирование текста вместе с картинками и поддержка NSAttachmentBehavior.

Для обработки тапа по NSTextAttachment в UITextView используется делегат UITextViewDelegate и метод textView(_:shouldInteractWith:in:interaction:). Этот метод вызывается, когда пользователь касается вложения, и позволяет выполнить переход на экран, открыть попап или воспроизвести анимацию.

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

Метод различает типы взаимодействия через параметр interaction: .preview (3D Touch / Haptic Touch), .default (обычный тап) и .presentActions (контекстное меню). Для каждого типа можно задать своё поведение или запретить его, вернув false.

При редактировании UITextView с NSTextAttachment важно помнить: удаление символа-заменителя (0xFFFC) удаляет и вложение. Пользователь видит картинку как единый элемент — она выделяется целиком, а не по пикселям. Для поддержки перетаскивания вложений в iOS 15+ используйте NSTextAttachmentViewProvider.

Типовые ошибки при работе с NSTextAttachment

Первая распространённая ошибка — игнорирование bounds. Разработчики часто полагаются на оригинальный размер изображения, что приводит к гигантским иконкам в тексте или, наоборот, к картинкам, которые едва видны. Всегда устанавливайте bounds явно с учётом шрифта и контекста.

Вторая ошибка — неправильное смещение по Y. Положительное значение в bounds.origin.y опускает картинку (в системе координат UIKit ось Y направлена вниз — это кажется нелогичным, но так работает Core Graphics). Для выравнивания по центру строки используйте формулу с capHeight шрифта, как показано в разделе 3.

Третья проблема — потеря изображения при change of traitCollection. Когда пользователь переключает Dark Mode или Dynamic Type, размер шрифта может измениться, а bounds останется прежним. Решение — вычислять bounds динамически в методе layoutSubviews или через KVO на font.

Четвёртая частая ошибка — использование NSTextAttachment в UILabel с numberOfLines > 1. При многострочном режиме и ограниченной ширине TextKit корректно переносит строки вместе с изображением. Проблема возникает, когда высота attachment превышает высоту строки — соседние строки наезжают друг на друга. Решение — увеличить lineSpacing через NSMutableParagraphStyle.

Часто задаваемые вопросы

Чем NSTextAttachment отличается от UIImageView в тексте?

NSTextAttachment делает изображение частью текстового потока: оно переносится, выравнивается и масштабируется вместе с текстом. UIImageView привязан к координатам супервью и не участвует в вёрстке текста.

Можно ли добавить NSTextAttachment в UILabel?

Да, если установить свойство attributedText вместо text. UILabel корректно отображает NSTextAttachment, но не поддерживает интерактив. Для тапов по вложению используйте UITextView.

Как изменить размер изображения после создания attachment?

Измените свойство bounds существующего экземпляра NSTextAttachment. Текст автоматически перерендерится с новыми размерами без необходимости создавать новый NSAttributedString.

Поддерживает ли NSTextAttachment анимированные изображения?

NSTextAttachment поддерживает статические изображения. Для GIF и анимированных форматов потребуется кастомная реализация через NSTextAttachmentViewProvider на iOS 15+ или через CADisplayLink.

Как добавить NSTextAttachment в текст программно?

Создайте экземпляр NSTextAttachment, установите image или data, задайте bounds, оберните в NSAttributedString(attachment:) и вставьте в NSMutableAttributedString через метод insert(_:at:).

Итоги

  • NSTextAttachment — класс UIKit для встраивания изображений, PDF и других медиа в форматированный текст.
  • Изображение добавляется через NSAttributedString(attachment:) и становится частью текстового потока.
  • Свойство bounds управляет размером и позицией: всегда задавайте его явно с учётом шрифта.
  • Для выравнивания иконки по центру строки используйте формулу с capHeight текущего шрифта.
  • PDF-вложения поддерживаются через инициализатор с data и корректным UTI-типом.
  • Для обработки тапа по вложению используйте UITextViewDelegate и метод shouldInteractWith.
  • При смене Dynamic Type пересчитывайте bounds динамически, чтобы избежать наложения строк.

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также