Генерация PDF-отчётов на Swift для iOS и macOS
Создание PDF-документов — одна из частых задач в мобильных и десктопных приложениях. На платформах Apple (iOS, macOS) для этого доступны мощные встроенные инструменты: PDFKit и Core Graphics. В этой статье мы разберём, как сформировать многостраничный отчёт с таблицами, текстом и графикой, используя только нативный Swift.
Почему стоит использовать встроенные инструменты?
- Не требует сторонних зависимостей — всё уже включено в SDK.
- Полный контроль над рендерингом — работа с координатами, шрифтами, цветами.
- Кроссплатформенность — код работает и на iOS, и на macOS.
- Высокая производительность — Core Graphics использует аппаратное ускорение.
Основные подходы
Существует два основных способа генерации PDF на Swift:
- PDFKit — высокоуровневый API для работы с PDF (чтение, редактирование, создание).
- Core Graphics — низкоуровневый рендеринг через контекст PDF.
Мы рассмотрим второй подход, так как он даёт максимальную гибкость при создании отчётов «с нуля».
Создание PDF-контекста
Первый шаг — создать PDF-контекст, в который будем рисовать элементы. Для этого используется функция UIGraphicsBeginPDFContextToFile (iOS) или её аналог для macOS.
import UIKit
func generatePDF() -> URL? {
let fileName = "Report.pdf"
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
guard let documentsURL = paths.first else { return nil }
let pdfURL = documentsURL.appendingPathComponent(fileName)
let pageSize = CGRect(x: 0, y: 0, width: 612, height: 792) // A4
UIGraphicsBeginPDFContextToFile(pdfURL.path, pageSize, nil)
// Здесь будем рисовать страницы
UIGraphicsEndPDFContext()
return pdfURL
}
Добавление страниц и контента
Каждая страница начинается с вызова UIGraphicsBeginPDFPage(). После этого можно использовать стандартные методы UIKit для рисования.
func drawReport() {
guard let pdfURL = generatePDF() else { return }
UIGraphicsBeginPDFContextToFile(pdfURL.path, CGRect(x: 0, y: 0, width: 612, height: 792), nil)
// Первая страница
UIGraphicsBeginPDFPage()
drawHeader(title: "Ежемесячный отчёт")
drawTable(data: sampleData)
// Вторая страница (если нужно)
UIGraphicsBeginPDFPage()
drawChart()
UIGraphicsEndPDFContext()
}
Рисование текста и заголовков
Для отрисовки текста используем NSString с атрибутами.
func drawHeader(title: String) {
let titleAttributes: [NSAttributedString.Key: Any] = [
.font: UIFont.boldSystemFont(ofSize: 24),
.foregroundColor: UIColor.darkGray
]
title.draw(at: CGPoint(x: 50, y: 40), withAttributes: titleAttributes)
}
Создание простой таблицы
Таблицу можно нарисовать с помощью линий и текста. Ниже пример генерации таблицы с двумя колонками.
func drawTable(data: [(String, String)]) {
let startX: CGFloat = 50
var startY: CGFloat = 100
let colWidth: CGFloat = 250
let rowHeight: CGFloat = 30
// Рисуем заголовки
let headerAttributes: [NSAttributedString.Key: Any] = [
.font: UIFont.boldSystemFont(ofSize: 14),
.foregroundColor: UIColor.black
]
"Название".draw(at: CGPoint(x: startX, y: startY), withAttributes: headerAttributes)
"Значение".draw(at: CGPoint(x: startX + colWidth, y: startY), withAttributes: headerAttributes)
startY += rowHeight
// Рисуем строки
for (key, value) in data {
let rowAttributes: [NSAttributedString.Key: Any] = [
.font: UIFont.systemFont(ofSize: 12),
.foregroundColor: UIColor.darkGray
]
key.draw(at: CGPoint(x: startX, y: startY), withAttributes: rowAttributes)
value.draw(at: CGPoint(x: startX + colWidth, y: startY), withAttributes: rowAttributes)
// Рисуем разделительную линию
let context = UIGraphicsGetCurrentContext()
context?.setStrokeColor(UIColor.lightGray.cgColor)
context?.setLineWidth(0.5)
context?.move(to: CGPoint(x: startX, y: startY + rowHeight))
context?.addLine(to Также в библиотеке
WebSocket библиотеки TypeScript: ws и Socket.IO – полное руководство
Proptest для Rust: полное руководство с примерами
Конфигурация приложений PHP: библиотеки и инструменты для гибкой настройки