Mojave与Catalina系统缩放后NSTextView宽度表现差异问题咨询
问题原因
- 你当前
setScaleFactor方法存在逻辑错误:你先将self.scaleFactor赋值为newScaleFactor后才计算scaler = newScaleFactor / self.scaleFactor,最终得到的scaler恒等于1,缩放逻辑实际没有正常生效。Mojave版本中NSScrollView的旧实现会自动修正该错误,Catalina重构了滚动视图和文本视图的交互逻辑,该错误直接导致坐标系统计算异常。 - Catalina版本对NSTextView默认配置做了变更:默认不再固定NSTextContainer的最大宽度,未手动配置的情况下会被判定为无限宽度,导致documentView的contentSize计算错误,出现无限横向滚动的问题。
- 缩放调用顺序错误:你先调用
setMagnification再修改documentView的坐标系统,Catalina中这两个操作的效果会叠加而非后者覆盖前者,进一步放大contentSize的计算偏差,同时触发系统自带的自动滚动到光标位置的特性,导致滚动跳转、偏移的异常表现。
修复方案
- 修正
setScaleFactor的逻辑顺序和文本容器配置:
- (void)setScaleFactor:(CGFloat)newScaleFactor { if (newScaleFactor != self.scaleFactor){ // 先计算缩放比值,再更新存储的缩放参数 CGFloat scaler = newScaleFactor / self.scaleFactor; self.scaleFactor = newScaleFactor; // 先修改文档视图的坐标系统,再设置滚动视图放大倍数,避免效果叠加 [self.documentView scaleUnitSquareToSize:NSMakeSize(scaler, scaler)]; [self setMagnification:newScaleFactor]; NSTextView *textView = (NSTextView *)self.documentView; NSTextContainer *tc = textView.textContainer; // 固定文本容器宽度跟随textView,避免无限拉伸 tc.widthTracksTextView = YES; // 按业务需求设置textView最大宽度,避免contentSize无限扩大 textView.maxSize = NSMakeSize(你的业务期望最大宽度, CGFLOAT_MAX); tc.size = NSMakeSize(textView.bounds.size.width, CGFLOAT_MAX); NSLayoutManager* lm = textView.layoutManager; [lm ensureLayoutForTextContainer:tc]; // 强制滚动视图重新计算内容尺寸 [self.contentView setNeedsLayout:YES]; [self layoutIfNeeded]; } }
- 关闭Catalina新增的自动滚动特性,避免滚动跳转到光标位置:
if (@available(macOS 10.15, *)) { // 关闭自动调整内边距 self.automaticallyAdjustsContentInsets = NO; // 关闭自动滚动到选中区域 self.automaticallyScrollsToActiveSelection = NO; }
- 检查NSTextView的自适应配置,确保不会随父视图无限拉伸:
textView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
内容的提问来源于stack exchange,提问作者Denis
相关产品推荐
相关产品推荐

