如何在Swift中使用PDFKit实现PDFAnnotation旋转?
Swift PDFKit 实现 PDFAnnotation 旋转的落地方案
原有代码失效原因
尝试实现旋转的参考代码为:annotation.bounds.origin = annotation.bounds.origin.applying(CGAffineTransform(rotationAngle: -90 * CGFloat.pi / 180.0))
该代码无法达到预期效果的核心逻辑问题是:PDFAnnotation的bounds是代表注解在PDF页面坐标系中的轴对齐占位矩形。仅对bounds的origin应用旋转仿射变换,本质只是对原点坐标做平移偏移,既不会改变注解内容的渲染方向,也不会自动适配旋转后的包围盒尺寸,极易导致注解被偏移到页面可视范围外,完全无法触发旋转渲染效果。
可行实现路径
- 固定步长旋转的原生API方案
PDFKit为PDFAnnotation提供了原生旋转方法setRotation(_:),该方法会直接在PDF注解的底层结构中写入标准的/Rotate属性,支持传入0、90、180、270四个代表顺时针旋转角度的整数值,渲染时会自动以注解bounds的几何中心为锚点完成内容旋转,不会出现位置偏移。
对应预期的-90度(逆时针旋转90度)效果,等价的顺时针旋转角度为270度,调用代码为:
注意:PDF坐标系默认原点在页面左下角、y轴向上,和UIKit坐标系方向存在差异,直接套用UI坐标系的旋转矩阵很容易出现位置错位。annotation.setRotation(270) - 任意角度旋转的自定义实现方案
如果需要实现非90度步长的任意角度旋转,原生*setRotation(_:)*方法无法满足需求时,可以通过自定义注解子类完成:- 基于原注解的bounds计算旋转后的轴对齐包围盒,通过
CGRectApplyAffineTransform将原bounds应用目标旋转矩阵,将得到的新矩形重新赋值给bounds属性,避免旋转后的内容被页面边缘裁剪 - 自定义PDFAnnotation子类,重写
draw(with:for:)方法:在绘制逻辑中先将当前图形上下文的坐标原点平移到原bounds的几何中心,应用目标角度的旋转仿射变换后再绘制注解的实际内容,绘制完成后还原上下文的变换状态,避免影响页面上其他元素的渲染
- 基于原注解的bounds计算旋转后的轴对齐包围盒,通过
- 效果生效注意事项
所有旋转相关的属性修改,必须在将注解添加到PDFPage之前完成。如果注解已经添加到页面后再修改旋转属性,很容易触发PDFKit的页面缓存机制,导致旋转效果无法实时同步到渲染层。
内容的提问来源于stack exchange,提问作者Sac Allen
相关产品推荐
相关产品推荐

