7

anがレイヤーバック( )NSTextViewのサブビューである場合、スペルミスのある単語の波状の赤い下線は表示されません。これを再現するために必要なのは、空のCocoaプロジェクトを作成し、ペン先を開き、ウィンドウにドラッグして、ウィンドウのコンテンツビューを切り替えてレイヤーを作成することだけです。ブーム-赤い下線はもうありません。NSView-wantsLayer == YESNSTextView

私はいくつかの検索を行いましたが、これは既知の状況のようであり、10.5から当てはまります。しかし、私が見つけられないのは、その回避策です。NSTextViewレイヤーバックビューにあるときに下線をレンダリングする方法はありませんか?

をオーバーライドし、レイアウトマネージャーを使用して、スペルミスを示す適切な一時属性が設定された適切な四角形を見つけて、自分で赤い波線を描くことを想像できますが、それはもちろん完全なハックNSTextViewです。drawRect:私はまた、Appleが10.7でこれを修正することを想像することができます(おそらく)そして突然私のアプリは二重の下線か何かを持つでしょう。


[更新]私の回避策

私の現在の回避策は、nptacekの言及されたスペルチェックデリゲートメソッドに触発され、以前は気づかなかったパスを深く掘り下げるように促されたので、その答えを受け入れますが、後世のために行ったことを投稿します。討論。

10.6.5を実行しています。NSClipViewのカスタムサブクラスのドキュメントビューであるNSTextViewのサブクラスがあります。これは、レイヤーがオンになっているウィンドウのcontentViewのサブビューです。これで遊んでいると、最終的にすべてのカスタマイズがコメントアウトされましたが、それでもスペルチェックが正しく機能していませんでした。

私は、2つの明確な問題が何であるかを特定しました。

#1は、NSTextViewがレイヤーに裏打ちされたビューでホストされている場合、スペルミスの下線をわざわざ描画することさえないということです。(Googleの検索に基づいて、10.5日間に下線が引かれた時期があったかもしれないが、正しい場所にはなかった可能性があることを収集しました。そのため、Appleは10.6でその問題を回避するために、それらを完全に無効にした可能性があります。わかりません。 。また、私が物を配置する方法などの副作用があり、私の場合はまったく表示されない可能性があります。現在は不明です。)

#2NSTextViewがこのレイヤー関連の状況にある場合、-isContinuousSpellCheckingEnabledがYESに設定されている場合でも、入力中にテキストのスペルが間違っていると正しくマークされていないように見えます。いくつかのスペルチェックデリゲートメソッドを実装し、NSTextViewが変更に関するメッセージを送信するのを見て、テキスト範囲をスペルミスとして設定するように通知することはありませんでした-テキストエディット(および他のテキストビューで赤い下線が表示される明らかにスペルミスの単語がある場合でも)他のアプリで)。また、NSTextViewの-handleTextCheckingResults:forRange:types:options:orthography:wordCount:をオーバーライドして、何が表示されているかを確認しましたが、同じものが表示されました。NSTextViewがカーソルの下の単語をスペルミスがないようにアクティブに設定していて、ユーザーがスペースを入力したり、スペースから離れたりしたときに、そうではなかったようです。tスペルミスがないか再確認します。しかし、私は完全にはわかりません。

さて、#1を回避するために、カスタムNSTextViewサブクラスの-drawRect:をオーバーライドして次のようにします。

- (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の動作とまったく同じようには機能しませんが、かなり近いものであり、今のところ作業は完了しています。うまくいけば、これは他の誰かに役立つか、もっと良いことに、誰かがここに来て、私が信じられないほど単純なものが欠けていると私に言い、それを修正する方法を説明します。:)

4

2 に答える 2

4

テキストの場合を除いて、CoreAnimationは素晴らしいです。レイヤーバックビュー(不透明なbackgroundColorを設定し、必ず背景を描画することで技術的に回避できます)を操作するときに、サブピクセルアンチエイリアスが指定されていないことに気付いたときに、これを直接体験しました。サブピクセルアンチエイリアシングは、テキストビューとレイヤーバックビューの操作中に発生する多くの警告の1つにすぎません。

この場合、いくつかのオプションがあります。可能であれば、テキストビューを利用するプログラムの部分のレイヤーバックビューから離れてください。すでにこれを試したことがあり、それを避けられない場合でも、希望はあります。

drawRectをオーバーライドすることなく、次のコードを使用して標準の動作に近いものを実現できます。


- (NSArray *)textView:(NSTextView *)view didCheckTextInRange:(NSRange)range types:(NSTextCheckingTypes)checkingTypes options:(NSDictionary *)options results:(NSArray *)results orthography:(NSOrthography *)orthography wordCount:(NSInteger)wordCount
{
     for(NSTextCheckingResult *myResult in results){
        if(myResult.resultType == NSTextCheckingTypeSpelling){
            NSMutableDictionary *attr = [[NSMutableDictionary alloc] init];
            [attr setObject:[NSColor redColor] forKey:NSUnderlineColorAttributeName];
            [attr setObject:[NSNumber numberWithInt:(NSUnderlinePatternDot | NSUnderlineStyleThick | NSUnderlineByWordMask)] forKey:NSUnderlineStyleAttributeName];
            [[inTextView layoutManager] setTemporaryAttributes:attr forCharacterRange:myResult.range];
            [attr release];
        }
    }
    return results;
}
基本的に、NSTextViewのデリゲートメソッド(必ずIBでデリゲートを設定してください!)を実行しています。このメソッドは、単語に不正なフラグが付けられているかどうかを確認し、正しくない場合は、色付きの下線を設定します。

このコードにはいくつかの問題があることに注意してください。つまり、ディセンダー(g、j、p、q、yなど)を含む文字はアンダースコアを正しく表示せず、スペルミス(文法チェックなし)についてのみテストされています。ここ!)。下線のドットパターン(NSUnderlinePatternDot)は、Appleのスペルチェックのスタイルと一致せず、ビューのレイヤーバッキングが無効になっている場合でもコードは有効になっています。さらに、このコードは迅速でダーティであり、メモリ管理などのチェックが行われていないため、他にも問題があると確信しています。

頑張って、Appleにバグレポートを提出してください。これがいつか過去のものになることを願っています!

于 2010-12-07T04:45:30.973 に答える
1

これもちょっとしたハックですが、私が作業できる唯一のことはNSTextView、すべてのセレクターが通過するように中間デリゲートを'sレイヤーに配置しdrawLayer:inContext:、NSTextView'sを呼び出すことdrawRect:でした。これは機能し、おそらくもう少し将来性がありますが、CALayerアニメーションが壊れるかどうかはわかりません。またCGContextRef、(バッキングレイヤーフレームに基づいて)のCTMを修正する必要があるようです。

編集:drawInContext:ドキュメント のように、を使用して図面を修正できますが、のCGContextGetClipBoundingBox(ctx)座標の反転に問題がある可能性がありますNSTextView

私がやったように呼び出すdrawRect:のは少しハックだので、これを修正する方法は完全にはわかりませんが、ネット上の誰かがそれを行うためのチュートリアルを持っていると確信しています。時間があれば作れるかもしれません。

代わりにこれを使用する方がおそらくはるかに適切であるため、NSCellバッキングを探す価値があるかもしれません。NSTextView

于 2010-12-06T22:28:47.287 に答える