Не секрет, что PDF документ в приложении можно показать в UIWebView. Но, что делать, если вас не устраивает то, как UIWebView отображает документ? Может быть вы хотите сделать свой механизм перехода по страницам?
В iOS PDF можно отобразить через CoreGraphics. При использовании этого подхода каждая страница рисуется отдельно. Т.е. если нужно сделать переход по страницам в документе — нужно будет все делать вручную.
Итак, предположим, что у нас в Bundle приложения лежит PDF-файл idevby.pdf. Как его отобразить? Создадим класс PDFView, который будет это отображать:
@interface PDFView : UIView
@end
В классе перекроем метод drawRect::
- (void)drawRect:(CGRect)rect
{
// путь до документа
CFURLRef url = (CFURLRef)[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"idevby" ofType:@"pdf"]];
// открываем документ
CGPDFDocumentRef pdfDocument = CGPDFDocumentCreateWithURL(url);
// если в документе нет страниц - ничего отображать не нужно
if ( CGPDFDocumentGetNumberOfPages(pdfDocument) > 0 )
{
// получим первую страницу (страницы нумеруются с первой)
CGPDFPageRef pdfPage = CGPDFDocumentGetPage(pdfDocument, 1);
// получим необходимое преобразование
CGAffineTransform t = CGPDFPageGetDrawingTransform(pdfPage, kCGPDFCropBox, self.bounds, 0, 1);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
// применим преобразование
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1, -1);
CGContextConcatCTM(context, t);
// отрисуем страницу
CGContextDrawPDFPage(context, pdfPage);
CGContextRestoreGState(context);
}
// закроем документ
CGPDFDocumentRelease(pdfDocument);
}
Рассмотрим основные моменты.
При отрисовке PDF-страницы мы сохраняем состояние контекста, а затем восстанавливаем его:
CGContextSaveGState(context);
...
CGContextRestoreGState(context);
Этого можно было бы и не делать, но если вы захотите рисовать что-то после отрисовки PDF-страницы — это необходимо, иначе то, что вы нарисуете может быть искривлено.
Нам необходимо отразить контекст по вертикали, иначе документ будет показан «вверх ногами». Это связано с тем, что в данном случае ось Y направлена снизу вверх.
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1, -1);
Ну и самое интересное:
CGAffineTransform t = CGPDFPageGetDrawingTransform(pdfPage, kCGPDFCropBox, self.bounds, 0, 1);
...
CGContextConcatCTM(context, t);
CGContextDrawPDFPage(context, pdfPage);
Функция CGPDFPageGetDrawingTransform возвращает трансформацию для контекста, которую нужно применить, чтобы целиком отобразить заданную область страницы в заданной области view. Трансформацию применяет функция CGContextConcatCTM. Первым аргументом функции CGPDFPageGetDrawingTransform является страница, которую хотим отобразить. Второй аргумент — область документа для отображения. Области определены так:
enum CGPDFBox {
kCGPDFMediaBox = 0,
kCGPDFCropBox = 1,
kCGPDFBleedBox = 2,
kCGPDFTrimBox = 3,
kCGPDFArtBox = 4
};
Третий аргумент — область на view, где будет отображена страница, в данном случае мы используем всю область. Четвертый аргумент — угол вращения в градусах, должен быть обязательно кратным 90. Пятый аргумент — сохранять ли пропорции сторон при отрисовке.
Конечно-же, этот способ более трудоемкий, чем способ с использованием UIWebView. Но, используя такой подход, мы можем получить больше возможностей для кастомизации отображения PDF. Есть и минус данного подхода — если в документе есть ссылки — они не будут активными и необходимо будет применять дополнительные средства.
На этом все, спасибо за внимание. Загрузить исходный код можно отсюда.