PDFKit:设备旋转时 PDFView 不调整大小
PDFKit: PDFView doesn't resize when device rotated
我有一个显示 PDFView 的 iPad 应用程序。该应用程序可旋转到任何方向。 PDFView 是全屏和单页的。以任一方向启动时,PDF 都会按预期显示;整个第一页是可见的,缩放到适合屏幕,没有任何 PDF 出现在屏幕外。 PDF 将始终是美国信纸大小的文档。
旋转时,PDF 会旋转,但不会调整大小。当旋转横向到纵向时,PDF 显示 "too small" - 外面有一个巨大的空边框。将纵向旋转为横向时,会显示 PDF 的顶部三分之二,底部的三分之一丢失在屏幕底部下方。
Autolayout 是在代码中配置的,非常简单(顶部、前导、高度和宽度)。
我查看了 Reveal 中的布局。它表明 PDFView 实际上正在按照 AutoLayout 配置正确调整大小。 PDFView 内部是一个(私有)PDFDocumentView,它不会调整大小。
我发现 "resize" 视图的唯一方法是在 viewWillTransitionToSize 中捕获旋转,从超级视图中删除 PDFView,并在将其放回之前完全重新配置视图(包括重新加载文档)在屏幕上。这是一个糟糕的用户体验。
我将代码提取到一个简单的单视图产品中。整个 UIViewController 的代码如下。下面还有来自 Reveal 的屏幕截图,显示了该问题。在这种情况下,我以纵向启动应用程序,旋转设备,然后截取这些屏幕截图。 (显示的 PDF 是 IRS 税表;我和应用程序都与 IRS 无关 - 它恰好是我使用的默认示例 PDF。)
#import "ViewController.h"
@import PDFKit;
@interface ViewController ()
@property (nonatomic, strong) PDFView *pdfView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self setupPDF];
}
-(void)setupPDF {
NSString *filename = @"myfile.pdf";
NSString *filenameWithoutPDF = [filename stringByReplacingOccurrencesOfString:@".pdf" withString:@""];
NSURL *url = [[NSBundle mainBundle] URLForResource:filenameWithoutPDF withExtension:@"pdf"];
NSData *data = [NSData dataWithContentsOfURL:url];
self.pdfView = [[PDFView alloc] init];
PDFDocument *document = [[PDFDocument alloc] initWithData:data];
self.pdfView.document = document;
self.pdfView.displayMode = kPDFDisplaySinglePage;
self.pdfView.autoScales = YES;
[self.view addSubview:self.pdfView];
[self setupConstraints];
}
-(void)setupConstraints {
[self.pdfView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.pdfView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.pdfView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.pdfView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.pdfView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0.0]];
}
@end
我发现 autoScales 值在旋转时重置为 NO,至少在某些情况下是这样。这似乎是 PDFKit 中的一个错误,在 WWDC 实验室讨论中得到确认。我已经使用以下代码解决了这个错误:
-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
self.pdfView.autoScales = YES;
}
我已经向 Apple 提交了错误;雷达 40848802 如果有人想欺骗它。
正如 Mitch 在另一个答案中所述,这绝对是 PDFKit 框架中的一个错误。但是,您可能 运行 遇到某些情况,每次设置 .autoScales = YES
时应用程序都会莫名其妙地崩溃。例如,尚未添加文档时。
下面我添加了一些我的代码,它检查文档是否实际显示在 PDFView 中并将 .autoScales
调用包装到 try catch 块中。我能够减轻自 iOS12 以来似乎出现的任何崩溃。
在我的例子中,PDFView 并没有直接添加到 ViewController,而是一个子视图。您也可以在 -(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
期间调用 fitPDFPage
。
- (void)fitPDFPage
{
if (self.legacyView) return;
if (@available(iOS 11.0, *))
{
if (!self.pdfView.document.pageCount) return;
self.pdfView.scaleFactor = self.pdfView.scaleFactorForSizeToFit;
self.pdfView.minScaleFactor = self.pdfView.scaleFactor;
@try
{
self.pdfView.autoScales = YES;
}
@catch (NSException *exception)
{
NSLog(@"PDFView Exception %@",exception);
}
}
}
- (void)layoutSubviews
{
[super layoutSubviews];
[self fitPDFPage];
}
我有一个显示 PDFView 的 iPad 应用程序。该应用程序可旋转到任何方向。 PDFView 是全屏和单页的。以任一方向启动时,PDF 都会按预期显示;整个第一页是可见的,缩放到适合屏幕,没有任何 PDF 出现在屏幕外。 PDF 将始终是美国信纸大小的文档。
旋转时,PDF 会旋转,但不会调整大小。当旋转横向到纵向时,PDF 显示 "too small" - 外面有一个巨大的空边框。将纵向旋转为横向时,会显示 PDF 的顶部三分之二,底部的三分之一丢失在屏幕底部下方。
Autolayout 是在代码中配置的,非常简单(顶部、前导、高度和宽度)。
我查看了 Reveal 中的布局。它表明 PDFView 实际上正在按照 AutoLayout 配置正确调整大小。 PDFView 内部是一个(私有)PDFDocumentView,它不会调整大小。
我发现 "resize" 视图的唯一方法是在 viewWillTransitionToSize 中捕获旋转,从超级视图中删除 PDFView,并在将其放回之前完全重新配置视图(包括重新加载文档)在屏幕上。这是一个糟糕的用户体验。
我将代码提取到一个简单的单视图产品中。整个 UIViewController 的代码如下。下面还有来自 Reveal 的屏幕截图,显示了该问题。在这种情况下,我以纵向启动应用程序,旋转设备,然后截取这些屏幕截图。 (显示的 PDF 是 IRS 税表;我和应用程序都与 IRS 无关 - 它恰好是我使用的默认示例 PDF。)
#import "ViewController.h"
@import PDFKit;
@interface ViewController ()
@property (nonatomic, strong) PDFView *pdfView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self setupPDF];
}
-(void)setupPDF {
NSString *filename = @"myfile.pdf";
NSString *filenameWithoutPDF = [filename stringByReplacingOccurrencesOfString:@".pdf" withString:@""];
NSURL *url = [[NSBundle mainBundle] URLForResource:filenameWithoutPDF withExtension:@"pdf"];
NSData *data = [NSData dataWithContentsOfURL:url];
self.pdfView = [[PDFView alloc] init];
PDFDocument *document = [[PDFDocument alloc] initWithData:data];
self.pdfView.document = document;
self.pdfView.displayMode = kPDFDisplaySinglePage;
self.pdfView.autoScales = YES;
[self.view addSubview:self.pdfView];
[self setupConstraints];
}
-(void)setupConstraints {
[self.pdfView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.pdfView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.pdfView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.pdfView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.pdfView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0.0]];
}
@end
我发现 autoScales 值在旋转时重置为 NO,至少在某些情况下是这样。这似乎是 PDFKit 中的一个错误,在 WWDC 实验室讨论中得到确认。我已经使用以下代码解决了这个错误:
-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
self.pdfView.autoScales = YES;
}
我已经向 Apple 提交了错误;雷达 40848802 如果有人想欺骗它。
正如 Mitch 在另一个答案中所述,这绝对是 PDFKit 框架中的一个错误。但是,您可能 运行 遇到某些情况,每次设置 .autoScales = YES
时应用程序都会莫名其妙地崩溃。例如,尚未添加文档时。
下面我添加了一些我的代码,它检查文档是否实际显示在 PDFView 中并将 .autoScales
调用包装到 try catch 块中。我能够减轻自 iOS12 以来似乎出现的任何崩溃。
在我的例子中,PDFView 并没有直接添加到 ViewController,而是一个子视图。您也可以在 -(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
期间调用 fitPDFPage
。
- (void)fitPDFPage
{
if (self.legacyView) return;
if (@available(iOS 11.0, *))
{
if (!self.pdfView.document.pageCount) return;
self.pdfView.scaleFactor = self.pdfView.scaleFactorForSizeToFit;
self.pdfView.minScaleFactor = self.pdfView.scaleFactor;
@try
{
self.pdfView.autoScales = YES;
}
@catch (NSException *exception)
{
NSLog(@"PDFView Exception %@",exception);
}
}
}
- (void)layoutSubviews
{
[super layoutSubviews];
[self fitPDFPage];
}