iOS开发中如何在旋转的PDFKit.PDFPage上绘制正向注释
iOS PDFKit旋转页面注释适配方案
坐标转换通用规则(对应问题Q1)
所有坐标计算的基准为页面未旋转时的媒体框(MediaBox)尺寸:先取rotation = 0状态下页面的媒体框宽高,记为originalPageWidth、originalPageHeight。
API返回的坐标规则固定为:原点在可见页面左下角、X轴向右延伸、Y轴向上延伸,先将接口返回的坐标组装为标准矩形:
let apiRect = CGRect( x: start_x, y: start_y, width: end_x - start_x, height: end_y - start_y )
根据页面当前rotation属性值(仅可能为0、90、180、270,顺时针递增),将API矩形转换为PDFKit当前页面坐标系可直接使用的矩形,规则如下:
rotation = 0:无需转换,直接使用apiRect即可rotation = 90:let convertedRect = CGRect( x: apiRect.minY, y: originalPageWidth - apiRect.maxX, width: apiRect.height, height: apiRect.width )rotation = 180:let convertedRect = CGRect( x: originalPageWidth - apiRect.maxX, y: originalPageHeight - apiRect.maxY, width: apiRect.width, height: apiRect.height )rotation = 270:let convertedRect = CGRect( x: originalPageHeight - apiRect.maxY, y: apiRect.minX, width: apiRect.height, height: apiRect.width )
注意:不要取旋转后页面的媒体框尺寸做计算,旋转后的媒体框会自动交换宽高,会导致坐标偏移。
注释边界与文本正向绘制实现(对应问题Q2)
不要通过在注释内嵌套UILabel的方式绘制文本,会受页面旋转上下文影响出现错位、消失问题,直接通过CoreGraphics在注释绘制回调中做矩阵抵消即可,步骤如下:
- 用上述步骤得到的
convertedRect初始化PDF注释对象,设置好背景色、边框样式后添加到对应页面。 - 重写注释的绘制方法,在绘制内容前对上下文做反向旋转变换,抵消页面旋转的影响,保证文本始终正向显示:
override func draw(with box: PDFDisplayBox, in context: CGContext) { // 先绘制注释默认的背景、边框 super.draw(with: box, in: context) context.saveGState() let currentRotation = self.page?.rotation ?? 0 let annoBounds = self.bounds // 根据页面旋转角度做反向矩阵变换 switch currentRotation { case 90: context.rotate(by: -.pi / 2) context.translateBy(x: -annoBounds.height, y: 0) case 180: context.rotate(by: .pi) context.translateBy(x: -annoBounds.width, y: -annoBounds.height) case 270: context.rotate(by: .pi / 2) context.translateBy(x: 0, y: -annoBounds.width) default: break } // 直接在修正后的上下文绘制文本 let textInset: CGFloat = 4 let textRect = CGRect( x: textInset, y: textInset, width: annoBounds.width - textInset * 2, height: annoBounds.height - textInset * 2 ) let content = "Sample Anno" as NSString content.draw(in: textRect, withAttributes: [ .font: UIFont.systemFont(ofSize: 14), .foregroundColor: UIColor.black ]) context.restoreGState() } - Xamarin.iOS环境下逻辑完全一致,仅需将语法替换为C#对应实现:用
CGAffineTransform.Rotate、Context.TranslateCTM实现矩阵变换,用NSString.DrawString完成文本绘制即可。
常见避坑点
- 不要直接修改页面的
rotation属性,会导致整个页面渲染方向错乱,所有适配逻辑都在注释侧完成即可。 - 无需套用通用任意角度旋转公式,PDFKit页面旋转角度只有四个固定值,硬编码四个场景的转换逻辑稳定性更高,不会出现随机偏移、文本缩放问题。
- 尽量不要依赖UIKit原生控件(如UILabel)作为注释内容,直接用CoreGraphics接口绘制,矩阵变换可控性更强,不会出现文本丢失问题。
内容的提问来源于stack exchange,提问作者Hung X. Tran
相关产品推荐
相关产品推荐

