PDFView添加NSView子视图后滚动不同步及PDFPage/PDFAnnotation失效问题求助
解决PDFView滚动时自定义子视图静止不动的问题
我之前做PDF标注功能的时候也踩过完全一样的坑,咱们一步步来拆解解决你的问题:
问题根源分析
你直接把CLMarkingView加到了PDFView本身,但PDFView的滚动逻辑是靠内部的documentView(页面容器视图)实现的——滚动时只有这个容器视图在移动,你加在PDFView上的子视图自然会停在原地。另外PDFAnnotation滚动后消失,大概率是坐标系没转换对,或者没把Annotation正确绑定到PDFPage上。
解决方案一:把自定义视图加到PDFView的documentView上(最推荐)
PDFView内部有个专门管理页面布局的documentView,把你的标注视图加到这个容器里,就能自动跟着页面滚动了:
// 替换原来的addSubview代码 m_markingView = [[CLMarkingView alloc] initWithFrame:[m_drawing.documentView bounds]]; [m_drawing.documentView addSubview:m_markingView]; [m_drawing setNeedsDisplay:YES];
注意:初始化CLMarkingView的frame时,要用documentView的bounds而不是PDFView的——因为documentView的坐标系和PDF文档的页面坐标系完全匹配,这样你的标注内容才能和PDF页面正确对齐。
解决方案二:修复PDFAnnotation滚动后消失的问题(回归官方API)
如果还是想尝试用官方的PDFAnnotation,需要注意这几个关键点:
- PDF页面坐标系以左下角为原点,和NSView的左上原点相反,绘制时要做坐标系转换
- 必须把Annotation添加到对应的PDFPage上,而不是直接加到PDFView
- 确保开启Annotation的显示开关
示例代码:
// 自定义Annotation子类 @interface CLMarkingAnnotation : PDFAnnotation @end @implementation CLMarkingAnnotation - (void)drawWithBox:(PDFDisplayBox)box inContext:(CGContextRef)context { // 转换坐标系:把PDF的左下原点转成NSView的左上原点 CGContextSaveGState(context); CGContextTranslateCTM(context, 0, self.bounds.size.height); CGContextScaleCTM(context, 1.0, -1.0); // 在这里绘制你的线条/文本,比如画一条红色直线 CGContextSetStrokeColorWithColor(context, [NSColor redColor].CGColor); CGContextSetLineWidth(context, 2.0); CGContextMoveToPoint(context, 50, 50); CGContextAddLineToPoint(context, 250, 250); CGContextStrokePath(context); CGContextRestoreGState(context); } @end // 添加Annotation到PDFPage的代码 CLMarkingAnnotation *markAnnotation = [[CLMarkingAnnotation alloc] initWithBounds:CGRectMake(0, 0, 300, 300) forType:PDFAnnotationTypeFreeText withProperties:nil]; markAnnotation.shouldDisplay = YES; // 添加到当前显示的PDFPage [[m_drawing currentPage] addAnnotation:markAnnotation]; [m_drawing setNeedsDisplay:YES];
这样添加的Annotation会和PDFPage绑定,滚动时会自动跟着页面移动,不会消失。
解决方案三:监听滚动事件同步更新自定义视图(不推荐,维护成本高)
如果坚持要把视图加在PDFView上,那你需要监听PDFView的滚动通知,手动同步视图位置:
// 初始化时添加通知监听 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pdfViewScrolled:) name:PDFViewBoundsChangedNotification object:m_drawing]; // 处理滚动回调 - (void)pdfViewScrolled:(NSNotification *)note { // 把PDFView的可见区域转换到documentView坐标系 NSRect visibleDocRect = [m_drawing convertRect:m_drawing.bounds toView:m_drawing.documentView]; // 更新标注视图的frame,让它跟着可见区域移动 m_markingView.frame = visibleDocRect; // 强制刷新视图 [m_markingView setNeedsDisplay:YES]; }
这个方案需要手动维护坐标系转换,容易出对齐bug,所以优先推荐前两个方案。
内容的提问来源于stack exchange,提问作者Young Shway
相关产品推荐
相关产品推荐

