在我的桌面Mac OS X应用程序中,我想以编程方式创建一个NSTextField“标签”,其行为和属性与在Interface Builder中创建的典型标签相同。
我通常使用(并且非常喜欢)IB,但在这种情况下,必须以编程方式完成。
尽可能地尝试,我似乎无法找到方法调用的组合,这些方法调用将以编程方式生成与从IB视图库调色板拖动的“标签”相同的标签行为。
任何人都可以提供或指出一些如何以编程方式执行此操作的示例代码吗? THX。
答案 0 :(得分:114)
标签实际上是NSTextField的一个实例,是NSView的子类。因此,由于它是NSView,因此必须将其添加到另一个视图中。
这是一个有效的代码:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSTextField *textField;
textField = [[NSTextField alloc] initWithFrame:NSMakeRect(10, 10, 200, 17)];
[textField setStringValue:@"My Label"];
[textField setBezeled:NO];
[textField setDrawsBackground:NO];
[textField setEditable:NO];
[textField setSelectable:NO];
[view addSubview:textField];
}
答案 1 :(得分:17)
从macOS 10.12开始(Sierra),有三个新的NSTextField
构造函数:
NSTextField(labelWithString:)
,标题文件注释显示“创建一个非包装,不可编辑,不可选择的文本字段,以默认系统字体显示文本。”
NSTextField(wrappingLabelWithString:)
,标题文件注释显示“创建一个包装,不可编辑,可选择的文本字段,以默认系统字体显示文本。”
NSTextField(labelWithAttributedString:)
,标题文件注释显示“创建一个不可编辑的,不可选择的文本字段,显示属性文本。此字段的换行模式由属性字符串的NSParagraphStyle属性决定。“
我测试了那些采用普通(非属性字符串)的文本字段,并创建了与故事板或xib中创建的文本字段类似但不完全相同的文本字段。
重要的区别在于两个构造函数都创建了一个文本字段,其中textBackgroundColor
(通常为纯白色)作为背景颜色,而故事板文本字段使用controlColor
(通常约为90%白色)。 / p>
不重要的是,两个构造函数也通过调用NSFont.systemFont(ofSize: 0)
来设置字体(它产生与我下面的代码不同的NSFont
对象,但是它们包含相同的底层Core Text字体。)
wrappingLabelWithString:
构造函数将字段isSelectable
设置为true
。 (这在头文件中有记录。)
我比较了四个NSTextField
实例:一个是通过将“Label”拖动到一个故事板创建的,另一个是通过将“Wrapping Label”拖动到一个故事板创建的,另一个是通过代码创建的。然后我仔细修改了代码创建标签的属性,直到它们的所有属性与storyboard创建的标签完全相同。结果是这两种方法:
extension NSTextField {
/// Return an `NSTextField` configured exactly like one created by dragging a “Label” into a storyboard.
class func newLabel() -> NSTextField {
let label = NSTextField()
label.isEditable = false
label.isSelectable = false
label.textColor = .labelColor
label.backgroundColor = .controlColor
label.drawsBackground = false
label.isBezeled = false
label.alignment = .natural
label.font = NSFont.systemFont(ofSize: NSFont.systemFontSize(for: label.controlSize))
label.lineBreakMode = .byClipping
label.cell?.isScrollable = true
label.cell?.wraps = false
return label
}
/// Return an `NSTextField` configured exactly like one created by dragging a “Wrapping Label” into a storyboard.
class func newWrappingLabel() -> NSTextField {
let label = newLabel()
label.lineBreakMode = .byWordWrapping
label.cell?.isScrollable = false
label.cell?.wraps = true
return label
}
}
如果您使用其中一种方法,请不要忘记设置字段的框架,或关闭其translatesAutoresizingMaskIntoConstraints
并添加约束。
以下是我用来比较不同文本字段的代码,以防您要检查:
import Cocoa
class ViewController: NSViewController {
@IBOutlet var label: NSTextField!
@IBOutlet var multilineLabel: NSTextField!
override func loadView() {
super.loadView()
}
override func viewDidLoad() {
super.viewDidLoad()
let codeLabel = NSTextField.newLabel()
let codeMultilineLabel = NSTextField.newWrappingLabel()
let labels = [label!, codeLabel, multilineLabel!, codeMultilineLabel]
for keyPath in [
"editable",
"selectable",
"allowsEditingTextAttributes",
"importsGraphics",
"textColor",
"preferredMaxLayoutWidth",
"backgroundColor",
"drawsBackground",
"bezeled",
"bezelStyle",
"bordered",
"enabled",
"alignment",
"font",
"lineBreakMode",
"usesSingleLineMode",
"formatter",
"baseWritingDirection",
"allowsExpansionToolTips",
"controlSize",
"highlighted",
"continuous",
"cell.opaque",
"cell.controlTint",
"cell.backgroundStyle",
"cell.interiorBackgroundStyle",
"cell.scrollable",
"cell.truncatesLastVisibleLine",
"cell.wraps",
"cell.userInterfaceLayoutDirection"
] {
Swift.print(keyPath + " " + labels.map({ ($0.value(forKeyPath: keyPath) as? NSObject)?.description ?? "nil" }).joined(separator: " "))
}
}
}
答案 2 :(得分:8)
要想做到这一点,这可能很棘手。我没有精确复制品的配方,但是当我遇到类似的情况时,我就是这样做的:
通过查看那里的所有无数值,你可以得到很多关于你忽略设置的猜测。通常它最终会成为挡板和边框设置的神奇组合,可以让你到达目的地。
答案 3 :(得分:5)
您可以尝试使用nib2objc获取IB设置的所有属性
答案 4 :(得分:2)
具体来说,您需要setBordered:NO
,并将挡板样式设置为我忘记的任何边框样式。还有setEditable:NO
,还有setSelectable:NO
。这应该足够了。
答案 5 :(得分:0)
Objective-C中反汇编的AppKit:
BOOL TMPSierraOrLater() {
static BOOL result = NO;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
result = [NSProcessInfo.processInfo isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){ 10, 12, 0 }];
});
return result;
}
@implementation NSTextField (TMP)
+ (instancetype)TMP_labelWithString:(NSString *)stringValue {
if (TMPSierraOrLater()) {
return [self labelWithString:stringValue];
}
NSParameterAssert(stringValue);
NSTextField *label = [NSTextField TMP_newBaseLabelWithoutTitle];
label.lineBreakMode = NSLineBreakByClipping;
label.selectable = NO;
[label setContentHuggingPriority:(NSLayoutPriorityDefaultLow + 1) forOrientation:NSLayoutConstraintOrientationHorizontal];
[label setContentHuggingPriority:NSLayoutPriorityDefaultHigh forOrientation:NSLayoutConstraintOrientationVertical];
[label setContentCompressionResistancePriority:NSLayoutPriorityDefaultHigh forOrientation:NSLayoutConstraintOrientationHorizontal];
[label setContentCompressionResistancePriority:NSLayoutPriorityDefaultHigh forOrientation:NSLayoutConstraintOrientationVertical];
label.stringValue = stringValue;
[label sizeToFit];
return label;
}
+ (instancetype)TMP_wrappingLabelWithString:(NSString *)stringValue {
if (TMPSierraOrLater()) {
return [self wrappingLabelWithString:stringValue];
}
NSParameterAssert(stringValue);
NSTextField *label = [NSTextField TMP_newBaseLabelWithoutTitle];
label.lineBreakMode = NSLineBreakByWordWrapping;
label.selectable = YES;
[label setContentHuggingPriority:NSLayoutPriorityDefaultLow forOrientation:NSLayoutConstraintOrientationHorizontal];
[label setContentHuggingPriority:NSLayoutPriorityDefaultHigh forOrientation:NSLayoutConstraintOrientationVertical];
[label setContentCompressionResistancePriority:NSLayoutPriorityDefaultLow forOrientation:NSLayoutConstraintOrientationHorizontal];
[label setContentCompressionResistancePriority:NSLayoutPriorityDefaultHigh forOrientation:NSLayoutConstraintOrientationVertical];
label.stringValue = stringValue;
label.preferredMaxLayoutWidth = 0;
[label sizeToFit];
return label;
}
+ (instancetype)TMP_labelWithAttributedString:(NSAttributedString *)attributedStringValue {
if (CRKSierraOrLater()) {
return [self labelWithAttributedString:attributedStringValue];
}
NSParameterAssert(attributedStringValue);
NSTextField *label = [NSTextField TMP_newBaseLabelWithoutTitle];
[label setContentHuggingPriority:NSLayoutPriorityDefaultLow forOrientation:NSLayoutConstraintOrientationHorizontal];
[label setContentHuggingPriority:NSLayoutPriorityDefaultHigh forOrientation:NSLayoutConstraintOrientationVertical];
[label setContentCompressionResistancePriority:NSLayoutPriorityDefaultLow forOrientation:NSLayoutConstraintOrientationHorizontal];
[label setContentCompressionResistancePriority:NSLayoutPriorityDefaultHigh forOrientation:NSLayoutConstraintOrientationVertical];
label.attributedStringValue = attributedStringValue;
[label sizeToFit];
return label;
}
#pragma mark - Private API
+ (instancetype)TMP_newBaseLabelWithoutTitle {
NSTextField *label = [[self alloc] initWithFrame:CGRectZero];
label.textColor = NSColor.labelColor;
label.font = [NSFont systemFontOfSize:0.0];
label.alignment = NSTextAlignmentNatural;
label.baseWritingDirection = NSWritingDirectionNatural;
label.userInterfaceLayoutDirection = NSApp.userInterfaceLayoutDirection;
label.enabled = YES;
label.bezeled = NO;
label.bordered = NO;
label.drawsBackground = NO;
label.continuous = NO;
label.editable = NO;
return label;
}
@end