如何自定义处于非活动状态的NSTextField / NSTextView的选定文本颜色

时间:2011-05-31 18:34:18

标签: cocoa nstextfield nstextfieldcell

我正在使用NSTextField并使用setupFieldEditorAttributes:方法自定义fieldEditor。这允许我为所选文本设置自定义前景色和背景色,这很重要,因为我的textField有黑色背景和白色文本。一般来说,这很好。但是,当我取消激活应用程序并且窗口不再是键时,我的设置似乎被覆盖。 fieldEditor NSTextView保留在那里,但绘制更改为白色文本颜色和浅灰色选择颜色(默认值)。有没有人有关于如何自定义此绘图的建议?

2 个答案:

答案 0 :(得分:0)

您可以覆盖[NSWindow willReturnFieldEditor:toObject:]并返回更改选择颜色的自定义NSTextView。

答案 1 :(得分:0)

受到 the answer to this question 的启发,解决方案是创建 NSLayoutManager 的覆盖,根据拥有它的 NSText 视图的第一响应者状态自定义执行突出显示的方式。

如果与此自定义布局管理器关联的文本视图是第一响应者,则它会使用 macOS 提供的颜色绘制选择。如果文本视图不是第一响应者,它将使用文本视图的背景颜色作为选择颜色,除非通过 setCustomInactiveColor 方法提供了自定义颜色。

// ---------------------------------------------------------------------------
//  IZLayoutManager CLASS
// ---------------------------------------------------------------------------
// Override NSLayoutManager to change how the currently selected text is
// highlighted when the owning NSTextView is not the first responder.

@interface IZLayoutManager : NSLayoutManager
{
}
-(instancetype)initWithOwningTextView:(NSTextView*)inOwningTextView;
@property (nullable, assign, nonatomic) NSTextView* owningTextView;
@property (nullable, strong, nonatomic) NSColor* customInactiveColor;
@end

@implementation IZLayoutManager

- (instancetype)initWithOwningTextView:(NSTextView*)inOwningTextView
{
    self = [super init];
    
    if (self)  {
        self.owningTextView = inOwningTextView;
    }
    
    return self;
}

- (void) dealloc
{
    // my project is non-ARC; so we maually release any custom color
    // we received; in non-ARC projects this is probably not necessary
    if (self.customInactiveColor != NULL) {
        [self.customInactiveColor release];
        self.customInactiveColor = NULL;
    }
    [super dealloc];
}

// see extensive description of fillBackgroundRectArray in NSLayoutManager.h
// TL;DR: if you change the background color here, you must restore it before
// returning from this call

- (void) fillBackgroundRectArray:(const NSRect *)rectArray count:(NSUInteger)rectCount forCharacterRange:(NSRange)charRange color:(NSColor *)color
{
    BOOL needToReestoreColor = NO;
    
    if (self.owningTextView != NULL && [[self.owningTextView window] firstResponder] != self.owningTextView) {
        if (self.customInactiveColor != NULL) {
            [self.customInactiveColor setFill];
        } else {
            [[self.owningTextView backgroundColor] setFill];
        }
        needToReestoreColor = true;
    }
    
    [super fillBackgroundRectArray:rectArray count:rectCount forCharacterRange:charRange color:color];
    
    if (needToReestoreColor) {
        [color setFill];
    }
}
@end

然后,在你分配了 NSTextView 之后,你需要这样做:

NSTextView* myTextView = ... // get a reference to your text view

// allocate our custom layout manager
IZLayoutManager* layoutManager = [[[IZLayoutManager alloc] initWithOwningTextView:self] autorelease];

// if you want to use a color other than the background for
// the selected text, uncomment the following line and
// supply your desired color

// [layoutManager setCustomInactiveColor:[NSColor redColor]];

[[myTextView textContainer] replaceLayoutManager:layoutManager];