Cocoa 更改窗口标题文本的颜色
我知道这不是一个流行的问题,有些人不喜欢非标准外观的应用程序,但它对我的应用程序很有用 是否可以通过“标准”非私有API方式更改NSWindow标题栏文本的颜色 我知道如果我使用私有API是可能的(但我认为不使用私有API是可能的,因为Pixelmator已经做到了,并且没有被MAS拒绝。我知道也可以通过制作无边界窗口并自己绘制所有内容来实现,但我认为Pixelmator并不是这样做的,因为他们仍然获得标准NSWind附带的所有附加位。)ow标题栏;可拖动图标、重命名窗口、用于文档修订的下拉菜单和全屏按钮 基本上,我使用setBackgroundColor创建了一个黑色窗口:但是文本仍然显示为黑色,这在黑色背景下不起作用Cocoa 更改窗口标题文本的颜色,cocoa,nswindow,Cocoa,Nswindow,我知道这不是一个流行的问题,有些人不喜欢非标准外观的应用程序,但它对我的应用程序很有用 是否可以通过“标准”非私有API方式更改NSWindow标题栏文本的颜色 我知道如果我使用私有API是可能的(但我认为不使用私有API是可能的,因为Pixelmator已经做到了,并且没有被MAS拒绝。我知道也可以通过制作无边界窗口并自己绘制所有内容来实现,但我认为Pixelmator并不是这样做的,因为他们仍然获得标准NSWind附带的所有附加位。)ow标题栏;可拖动图标、重命名窗口、用于文档修订的下拉菜单
那么,有人知道这样做的方法吗,或者Pixelmator是如何做到的?您可以使用一些私人API解决问题的评论中提到的问题-但是,您将无法将该应用提交到AppStore 另一个解决方案是获取
[[myWindow contentView]superview]
——这将获得前面提到的NSThemeView
实例。然后只需搜索视图的子视图(实际上称为框架视图)NSTextField的任何实例的子视图,并修改这些子视图。请注意,这些私有视图的层次结构可能会随着每个OS X版本的变化而变化,这可能会破坏您的代码
最好的解决方案可能是子类化(只有子类,没有其他定制)
NSWindow
,并实现-title
和-setTitle:
方法-对于每个窗口,您可以将实际标题设置为@”“
(通过调用[super setTitle:@”“]
)然后将您自己的、以编程方式创建的NSTextField
实例放入框架视图(即[[self-contentView]superview]addSubview:myTextField]
,其中myTextField
是文本字段。您需要确定字段的确切位置等,但这是最简单的部分。这是Swift中的一个解决方案。时间太晚了,我很累,所以这可能不是最佳方案,但它很有效
首先,这里有一个在层次结构中查找视图的函数,可以选择跳过特定视图。(如果我们要搜索窗口.contentView.superview.subviews
,并且希望忽略contentView
中您自己的视图,这将非常有用。)
下面是如何使用它,例如从NSViewController
子类。请注意,您需要在窗口可见时执行此操作,因此无法在viewDidLoad
中执行此操作
override func viewDidAppear() {
if let windowContentView = view.window?.contentView as? NSView {
if let windowContentSuperView = windowContentView.superview {
let titleView = findViewInSubview(windowContentSuperView.subviews as [NSView], ignoreView: windowContentView) { (view) -> Bool in
// We find the title by looking for an NSTextField. You may
// want to make this test more strict and for example also
// check for the title string value to be sure.
return view is NSTextField
}
if let titleView = titleView as? NSTextField {
titleView.attributedStringValue = NSAttributedString(string: "Hello", attributes: [NSForegroundColorAttributeName: NSColor.redColor()])
}
}
}
}
请注意,您正在玩火。像这样的内部构件没有指定是有原因的。因为OS X 10.10,它应该足以将窗口的外观更改为NSAppearanceNameVibrantDark
window.appearance = NSAppearance(named:NSAppearanceNameVibrantDark)
我觉得值得一提,因为你能找到的大多数答案都过时了。我就是这样做的:
#import <objc/runtime.h>
@interface SOWindow : NSWindow
@end
@interface SOWindowFrameOverrides : NSView
@end
@implementation SOWindow
+ (void)load
{
SEL selector = NSSelectorFromString(@"_currentTitleColor");
SEL originalSelector = NSSelectorFromString(@"_original_currentTitleColor");
Class frameClass = NSClassFromString(@"NSThemeFrame");
Method m = class_getInstanceMethod(frameClass, selector);
Method m2 = class_getInstanceMethod([SOWindowFrameOverrides class], selector);
class_addMethod(frameClass, originalSelector, method_getImplementation(m), method_getTypeEncoding(m));
method_exchangeImplementations(m, m2);
}
@end
@implementation SOWindowFrameOverrides
- (NSColor *)_currentTitleColor
{
if ([self.window isKindOfClass:[SOWindow class]]) {
return [NSColor redColor];
} else {
return [self _original_currentTitleColor];
}
}
- (NSColor *)_original_currentTitleColor
{
// will be filled in at runtime
return nil;
}
@end
#导入
@界面SOWindow:NSWindow
@结束
@接口SOWindowFrameOverrides:NSView
@结束
@索文多的实施
+(空)荷载
{
SEL selector=NSSelectorFromString(@“_currentTitleColor”);
SEL originalSelector=NSSelectorFromString(@“\u original\u currentTitleColor”);
类frameClass=NSClassFromString(@“NSThemeFrame”);
方法m=class\u getInstanceMethod(框架类,选择器);
方法m2=class_getInstanceMethod([SOWindowFrameOverrides class],选择器);
class_addMethod(frameClass,originalSelector,method_getImplementation(m),method_getTypeEncoding(m));
方法交换实施(m,m2);
}
@结束
@wframeOverrides的实现
-(非彩色*)\u当前标题颜色
{
if([self.window是类的种类:[SOWindow class]]){
返回[NSColor redColor];
}否则{
返回[self\u original\u currentTitleColor];
}
}
-(非彩色*)\u原色\u当前标题颜色
{
//将在运行时填写
返回零;
}
@结束
虽然视图层次结构从Mavericks到Yosemite已经发生了很大的变化,\u currentTitleColor
已经在API中出现了很长一段时间,并且在不久的将来可能不会改变。即使是艰难的方法swizzling也是一种黑客方式,我发现它比遍历视图层次结构更优雅,但这只是我自己
如果您想进一步自定义标题,可以覆盖
NSThemeFrame
上的\u titleTextField
以返回自定义文本字段(我已使用它更改项目的背景样式).我懒得尝试这个,但我想知道如果你得到窗口的内容视图并要求它提供其超级视图,你会得到什么。可能你会得到零,或者你会得到一个包含其他隐藏内容的根视图。你会得到一个名为NSThemeView的私有NSView子类。它确实包含一些关于窗口关闭、最小化和最大化的私有视图mise按钮,但我不知道如何在不使用私有API的情况下访问标题。Matt Gallagher有一篇关于自定义窗口的文章,你应该可以在那里找到一些信息。正如问题中提到的,我不想做自定义窗口,我已经发布了答案。请检查我的This对我有效,但它似乎可以绘制文本twice。第一个文本是正常绘制的,正如所需,但第二个文本有点不对劲。这让它看起来很奇怪。你知道如何解决这个问题吗?这个方法对我很有效。但你仍然需要在设置titleView.attributedStringValue之前设置NSWindow.title,以便标题文本可以正确布局。不使用面板。。。“无法识别的选择器”\u backstoppedByDefaultAppearance
“NSAppearanceNameVibrantDark看起来不错,但它似乎在我基于OpenGL的应用程序中造成了问题……它似乎创建了半透明的窗口栏,似乎使用了CoreAni
#import <objc/runtime.h>
@interface SOWindow : NSWindow
@end
@interface SOWindowFrameOverrides : NSView
@end
@implementation SOWindow
+ (void)load
{
SEL selector = NSSelectorFromString(@"_currentTitleColor");
SEL originalSelector = NSSelectorFromString(@"_original_currentTitleColor");
Class frameClass = NSClassFromString(@"NSThemeFrame");
Method m = class_getInstanceMethod(frameClass, selector);
Method m2 = class_getInstanceMethod([SOWindowFrameOverrides class], selector);
class_addMethod(frameClass, originalSelector, method_getImplementation(m), method_getTypeEncoding(m));
method_exchangeImplementations(m, m2);
}
@end
@implementation SOWindowFrameOverrides
- (NSColor *)_currentTitleColor
{
if ([self.window isKindOfClass:[SOWindow class]]) {
return [NSColor redColor];
} else {
return [self _original_currentTitleColor];
}
}
- (NSColor *)_original_currentTitleColor
{
// will be filled in at runtime
return nil;
}
@end