NSTextView在图层上没有显示红色拼写错误的下划线
当
NSTextView
是NSView
的子视图时,它是层支持的(-wantsLayer == YES
),它不会为拼写错误的单词渲染波浪形的红色下划线。重现这一点就是制作一个空的Cocoa项目,打开笔尖,将NSTextView
拖到窗口中,然后切换窗口的内容视图以获得一个图层。繁荣 - 没有更多的红色下划线。
我做了一些搜索,这似乎是一个已知的情况,自10.5以来一直如此。但是,我找不到的是它的解决方法。当NSTextView
在图层支持的视图中时,是否无法获取下划线?
我可以想象覆盖NSTextView
的drawRect:
并使用布局管理器找到适当的临时属性集,指示拼写错误,然后自己绘制红色曲线,但这当然是完全黑客攻击。我也可以想象苹果公司在10.7(或许)中修复此问题,突然我的应用程序会有双重下划线或其他东西。
[更新]我的解决方法
我当前的解决方法受到nptacek提到的拼写检查委托方法的启发,这促使我深入挖掘我之前没有注意到的路径,所以我将接受这个答案,但是发布了我为后代所做的和/或进一步的讨论。
我正在运行10.6.5。我有一个NSTextView的子类,它是NSClipView的自定义子类的文档视图,后者又是我的窗口contentView的子视图,它打开了图层。在玩这个时,我最终将所有自定义注释掉,但拼写检查仍然无法正常工作。
我相信,我发现了两个截然不同的问题:
#1是NSTextView,当托管在图层支持的视图中时,甚至不打算绘制拼写错误的下划线。 (我根据谷歌的搜索结果表明,它可能在10.5天内有时间提取下划线,但不是在正确的位置 - 所以Apple可能只是完全禁用它们以避免10.6中的问题。我不确定我的定位方式也可能有一些副作用,导致它们在我的情况下根本不会出现。目前未知。)
#2是当NSTextView处于与图层相关的情况时,即使将-isContinuousSpellCheckingEnabled设置为YES,它在您输入时似乎也没有正确地将文本标记为拼写错误。我通过实现一些拼写检查委托方法来验证这一点并观察NSTextView发送有关更改的消息但从未通知将任何文本范围设置为拼写错误 - 即使显示拼写错误的单词会在TextEdit中显示红色下划线(和其他文本视图在其他应用程序中)。我还覆盖了NSTextView的-handleTextCheckingResults:forRange:types:options:orthography:wordCount:看看它看到了什么,它看到了同样的东西。就好像NSTextView正在主动设置光标下的单词没有拼写错误,然后当用户键入空格或远离它或其他任何东西时,它没有重新检查拼写错误。不过,我不完全确定。
好的,所以要解决#1,我覆盖-drawRect:在我的自定义NSTextView子类中看起来像这样:
- (void)drawRect:(NSRect)rect
{
[super drawRect:rect];
[self drawFakeSpellingUnderlinesInRect:rect];
}
然后我实现了-drawFakeSpellingUnderlinesInRect:使用layoutManager获取包含NSSpellingStateAttributeName作为临时属性的文本范围,并渲染一个合理接近标准OSX拼写错误点图案的点图案。
- (void)drawFakeSpellingUnderlinesInRect:(NSRect)rect
{
CGFloat lineDash[2] = {0.75, 3.25};
NSBezierPath *underlinePath = [NSBezierPath bezierPath];
[underlinePath setLineDash:lineDash count:2 phase:0];
[underlinePath setLineWidth:2];
[underlinePath setLineCapStyle:NSRoundLineCapStyle];
NSLayoutManager *layout = [self layoutManager];
NSRange checkRange = NSMakeRange(0,[[self string] length]);
while (checkRange.length > 0) {
NSRange effectiveRange = NSMakeRange(checkRange.location,0);
id spellingValue = [layout temporaryAttribute:NSSpellingStateAttributeName atCharacterIndex:checkRange.location longestEffectiveRange:&effectiveRange inRange:checkRange];
if (spellingValue) {
const NSInteger spellingFlag = [spellingValue intValue];
if ((spellingFlag & NSSpellingStateSpellingFlag) == NSSpellingStateSpellingFlag) {
NSUInteger count = 0;
const NSRectArray rects = [layout rectArrayForCharacterRange:effectiveRange withinSelectedCharacterRange:NSMakeRange(NSNotFound,0) inTextContainer:[self textContainer] rectCount:&count];
for (NSUInteger i=0; i<count; i++) {
if (NSIntersectsRect(rects[i], rect)) {
[underlinePath moveToPoint:NSMakePoint(rects[i].origin.x, rects[i].origin.y+rects[i].size.height-1.5)];
[underlinePath relativeLineToPoint:NSMakePoint(rects[i].size.width,0)];
}
}
}
}
checkRange.location = NSMaxRange(effectiveRange);
checkRange.length = [[self string] length] - checkRange.location;
}
[[NSColor redColor] setStroke];
[underlinePath stroke];
}
所以在这样做之后,我可以看到红色下划线,但它似乎没有更新我输入的拼写状态。为了解决这个问题,我在NSTextView子类中实现了以下恶意攻击:
- (void)setNeedsFakeSpellCheck
{
if ([self isContinuousSpellCheckingEnabled]) {
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(forcedSpellCheck) object:nil];
[self performSelector:@selector(forcedSpellCheck) withObject:nil afterDelay:0.5];
}
}
- (void)didChangeText
{
[super didChangeText];
[self setNeedsFakeSpellCheck];
}
- (void)updateInsertionPointStateAndRestartTimer:(BOOL)flag
{
[super updateInsertionPointStateAndRestartTimer:flag];
[self setNeedsFakeSpellCheck];
}
- (void)forcedSpellCheck
{
[self checkTextInRange:NSMakeRange(0,[[self string] length]) types:[self enabledTextCheckingTypes] options:nil];
}
它的工作方式与真正的,预期的OSX行为完全不同,但它有点紧密,现在就完成了工作。希望这对其他人有帮助,或者更好的是,有人来到这里告诉我,我错过了一些非常简单的东西,并解释了如何解决它。 :)
没有找到相关结果
已邀请:
2 个回复
昧伎
我们基本上是为NSTextView做一个快速而又脏的委托方法(确保在IB中设置委托!),它检查单词是否被标记为不正确,如果是,则设置彩色下划线。 请注意,此代码存在一些问题 - 即具有下行符(例如,g,j,p,q,y)的字符将无法正确显示下划线,并且仅测试拼写错误(无语法检查)这里!)。下划线圆点图案(NSUnderlinePatternDot)与拼写检查的Apple样式不匹配,即使为视图禁用了图层背景,代码仍然启用。另外,我确定还有其他问题,因为这段代码很快而且很脏,而且还没有检查内存管理或其他任何问题。 祝你好运,向Apple提交文件错误报告,希望有一天会成为过去!
购藏盗码韦
的层上放置一个中间委托,以便所有选择器都通过,但是
然后调用NSTextView的
。虽然我不确定它是否会打破任何CALayer动画,但这可能会有一些未来的证据。你似乎也必须修复
的CTM(基于背衬层框架?)。 编辑: 你可以像
文档中那样使用
获得绘图矩形,但是在
中可能存在翻转坐标的问题。 我并不完全确定如何解决这个问题,因为我打电话给ѭѭ有点像hackish,但我确信网上有人会做一个教程。如果我有时间并且有时间,我也许可以制作一个。 寻找支持
的
可能是值得的,因为使用它可能更合适。