何时调整打印用NSView大小?适配页面与记录数的最佳时机
解决Cocoa打印NSView动态适配尺寸的问题
我之前在做自定义打印视图的时候也踩过类似的坑,-beginDocument确实太晚了——这时候打印系统已经完成了初始的页数计算,所以预览会出现页数不准的问题。结合Cocoa打印流程的实践,给你几个靠谱的实现方式:
1. 重写-printOperationWithSettings:error:提前调整尺寸
这个方法是创建打印操作的早期入口,在打印面板显示前就能拿到完整的打印设置,是调整视图尺寸的黄金时机。你可以在这里基于NSPrintInfo的纸张参数计算视图大小,再生成打印操作:
- (NSPrintOperation *)printOperationWithSettings:(nullable NSDictionary<NSPrintInfoAttributeKey, id> *)printSettings error:(NSError * _Nullable __autoreleasing *)error { // 获取打印信息 NSPrintInfo *printInfo = [NSPrintInfo printInfoWithDictionary:printSettings]; // 计算纸张可用宽度(减去左右边距) CGFloat pageWidth = printInfo.paperSize.width - printInfo.leftMargin - printInfo.rightMargin; // 根据记录数量计算内容总高度 CGFloat contentHeight = [self calculateContentHeightForPageWidth:pageWidth]; // 设置视图完整尺寸(包含边距) self.frame = CGRectMake(0, 0, printInfo.paperSize.width, contentHeight + printInfo.topMargin + printInfo.bottomMargin); // 调用父类方法生成最终打印操作 return [super printOperationWithSettings:printSettings error:error]; } // 抽离内容高度计算逻辑,方便多处复用 - (CGFloat)calculateContentHeightForPageWidth:(CGFloat)pageWidth { CGFloat totalHeight = 0; // 根据你的记录数据、每条记录的高度逻辑计算总高度 for (id record in self.printRecords) { totalHeight += [self heightForSingleRecord:record withAvailableWidth:pageWidth]; } return totalHeight; }
2. 使用-prepareForPrinting钩子做打印准备
Cocoa专门提供了-prepareForPrinting方法,用于在打印开始前完成视图的准备工作。这个方法会在打印面板弹出前被调用,同样能提前拿到printInfo,调整尺寸后预览会正确计算页数:
- (void)prepareForPrinting { [super prepareForPrinting]; NSPrintInfo *printInfo = self.printInfo; CGFloat pageWidth = printInfo.paperSize.width - printInfo.leftMargin - printInfo.rightMargin; CGFloat contentHeight = [self calculateContentHeightForPageWidth:pageWidth]; // 如果是基于frame布局,直接设置frame self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, printInfo.paperSize.width, contentHeight + printInfo.topMargin + printInfo.bottomMargin); // 如果用Auto Layout,建议更新高度约束的constant值 self.contentHeightConstraint.constant = contentHeight; [self layoutIfNeeded]; }
3. 处理打印设置变更的场景
如果用户在打印面板里修改了纸张尺寸、方向或者边距,你需要及时更新视图大小。可以通过重写-updatePrintInfo:来响应:
- (void)updatePrintInfo:(NSPrintInfo *)newPrintInfo { [super updatePrintInfo:newPrintInfo]; // 重新计算并调整视图尺寸 CGFloat pageWidth = newPrintInfo.paperSize.width - newPrintInfo.leftMargin - newPrintInfo.rightMargin; CGFloat contentHeight = [self calculateContentHeightForPageWidth:pageWidth]; self.frame = CGRectMake(0, 0, newPrintInfo.paperSize.width, contentHeight + newPrintInfo.topMargin + newPrintInfo.bottomMargin); }
关键注意点
- 绝对避免在
-beginDocument或打印循环的后期方法里调整尺寸:此时打印系统已经完成了页数估算,修改视图大小不会同步到预览。 - 如果使用Auto Layout,优先通过修改约束来调整尺寸,而不是直接设置frame/bounds,避免布局冲突。
- 测试时要多切换纸张尺寸和方向,确认预览和实际打印的页数完全一致。
内容的提问来源于stack exchange,提问作者uliwitness
相关产品推荐
相关产品推荐

