Mac 应用中的程序化 NSLayoutConstraint 调整了 window contentView 的大小
programmatic NSLayoutConstraint in Mac app resizes window contentView
我正在尝试让自动布局在 Objective-C Mac 应用程序中以编程方式工作。
目标非常基本,一个简单的类似工具栏的视图横跨 window 顶部。高度不应改变,视图应位于 window 的顶部,宽度应随 window.
调整大小
当我在 .xib 中配置它时,效果很好。无需担心高度,我只需添加从自定义视图到超级视图(即 NSWindow 的 contentView)的前导、尾随和顶部约束连接。我不必更改任何优先级或其他设置。
我需要以编程方式执行此操作,在代码中创建 window、子视图和约束。我试过同时使用锚点和 NSLayoutConstraint 对象(均已参数化并基于视觉布局字符串)。在所有情况下,我都会遇到一个奇怪的行为,即 window 的 contentView 调整大小,降低到高度为零,并且没有任何内容被绘制到屏幕上。
这是一种完整的方法,使用锚点:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// make window
NSRect windowRect = NSMakeRect(0.0, 0.0, 900.0, 200.0);
NSWindowStyleMask windowStyle = NSWindowStyleMaskTitled
| NSWindowStyleMaskClosable
| NSWindowStyleMaskResizable
| NSWindowStyleMaskMiniaturizable;
NSWindow * win = [[NSWindow alloc] initWithContentRect:windowRect
styleMask:windowStyle
backing:NSBackingStoreBuffered
defer:NO];
win.title = @"Window Made in Code";
win.contentView.translatesAutoresizingMaskIntoConstraints = NO;
// add view
NSRect viewFrame = windowRect;
viewFrame.size.height = 80.0;
viewFrame.origin.y = 120.0;
NSView * view = [[MyView alloc] initWithFrame:viewFrame];
[win.contentView addSubview:view];
[view setNeedsDisplay:YES];
// add constraints
[view.leadingAnchor constraintEqualToAnchor:win.contentView.leadingAnchor].active = YES;
[view.trailingAnchor constraintEqualToAnchor:win.contentView.trailingAnchor].active = YES;
[view.topAnchor constraintEqualToAnchor:win.contentView.topAnchor].active = YES;
// note, the above also tried using layoutMargins of superview, same behavior
// show window
[win setIsVisible:YES];
[win center];
self.codeWindow = win;
[self.codeWindow makeKeyAndOrderFront:NSApp];
}
如果我不添加约束,一切都会正确绘制,但正如预期的那样,子视图不会随着 window.
调整大小
当我添加约束时,超级视图(window 的 contentView) 的大小调整为高度 0,因此不会绘制任何内容。如果我省略顶部约束,这不会发生,但是水平约束会向后工作:而不是在 window 调整大小时调整子视图的大小,它们会阻止 Window contentView 水平调整大小;我仍然可以将 window 拖动得更大,但调试时发现内容视图框架宽度没有增加。
这是我也尝试使用 NSLayoutConstraint 工厂方法的替代代码方法;我在这里设置优先级,但没有不同的优先级纠正行为:
NSLayoutConstraint * leadingC = [NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:view.superview
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:0.0];
leadingC.priority = NSLayoutPriorityDragThatCannotResizeWindow;
NSLayoutConstraint * trailingC = [NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:view.superview
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:0.0];
trailingC.priority = NSLayoutPriorityDragThatCannotResizeWindow;
NSLayoutConstraint * topC = [NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:view.superview
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0];
[NSLayoutConstraint activateConstraints:@[leadingC, trailingC, topC]];
[view.superview addConstraints:self.constraints];
因为我尝试这几种不同的方法得到了同样糟糕的结果,所以我觉得我一定是完全遗漏了 NSLayoutConstraint 的某些东西,但我无法从教程或文档中弄清楚。我确实在运行时通过调试布局约束在 .xib 和代码创建的 windows 之间进行了比较,但无法从差异中重建我做错了什么,除了 .xib 超级视图具有 NSAutoresizingMaskLayoutConstraint 对象。
如果我注释掉 win.contentView.translatesAutoresizingMaskIntoConstraints = NO;
我确实会以编程方式调整大小行为,但这让我感到困惑 - 我认为当我们创建显式约束时我们应该将该标志设置为 NO?
感谢您就如何实现此功能提出任何建议!
当您选择加入约束时,您必须用约束完整地描述视图的大小。在这种情况下,您已经指定了工具栏的宽度,并设置了它的位置,但看起来您正试图用最初提供给视图的框架来固定高度。你还必须有一个约束来设置它的高度。
同时 translatesAutoresizingMaskIntoConstraints
描述了视图如何与其父视图相关,而不是与其子视图相关。所以你应该在工具栏视图上设置它,而不是 window 的 contentView。试试这个代码:
#import "AppDelegate.h"
@interface AppDelegate ()
@end
@interface MyView : NSView
@end
@implementation MyView
- (void)drawRect:(NSRect)dirtyRect
{
CGContextRef cgContext = [[NSGraphicsContext currentContext] CGContext];
CGContextSetFillColorWithColor(cgContext, [[NSColor yellowColor] CGColor]);
CGContextFillRect(cgContext, self.bounds);
}
@end
@implementation AppDelegate
{
NSWindowController *disjointController;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSRect windowRect = NSMakeRect(0.0, 0.0, 900.0, 200.0);
NSWindowStyleMask windowStyle = NSWindowStyleMaskTitled
| NSWindowStyleMaskClosable
| NSWindowStyleMaskResizable
| NSWindowStyleMaskMiniaturizable;
NSWindow * win = [[NSWindow alloc] initWithContentRect:windowRect
styleMask:windowStyle
backing:NSBackingStoreBuffered
defer:NO];
win.title = @"Window Made in Code";
// add view
NSView *view = [[MyView alloc] initWithFrame: windowRect];
view.translatesAutoresizingMaskIntoConstraints = NO;
view.layer.backgroundColor = [[NSColor yellowColor] CGColor];
[win.contentView addSubview: view];
// add constraints
[view.leadingAnchor constraintEqualToAnchor: win.contentView.leadingAnchor].active = YES;
[view.trailingAnchor constraintEqualToAnchor: win.contentView.trailingAnchor].active = YES;
[view.topAnchor constraintEqualToAnchor: win.contentView.topAnchor].active = YES;
[view.heightAnchor constraintEqualToConstant: 80].active = YES;
// show window
[win center];
disjointController = [[NSWindowController alloc] initWithWindow: win];
[win makeKeyAndOrderFront:NSApp];
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
- (BOOL)applicationSupportsSecureRestorableState:(NSApplication *)app {
return YES;
}
@end
我正在尝试让自动布局在 Objective-C Mac 应用程序中以编程方式工作。
目标非常基本,一个简单的类似工具栏的视图横跨 window 顶部。高度不应改变,视图应位于 window 的顶部,宽度应随 window.
调整大小当我在 .xib 中配置它时,效果很好。无需担心高度,我只需添加从自定义视图到超级视图(即 NSWindow 的 contentView)的前导、尾随和顶部约束连接。我不必更改任何优先级或其他设置。
我需要以编程方式执行此操作,在代码中创建 window、子视图和约束。我试过同时使用锚点和 NSLayoutConstraint 对象(均已参数化并基于视觉布局字符串)。在所有情况下,我都会遇到一个奇怪的行为,即 window 的 contentView 调整大小,降低到高度为零,并且没有任何内容被绘制到屏幕上。
这是一种完整的方法,使用锚点:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// make window
NSRect windowRect = NSMakeRect(0.0, 0.0, 900.0, 200.0);
NSWindowStyleMask windowStyle = NSWindowStyleMaskTitled
| NSWindowStyleMaskClosable
| NSWindowStyleMaskResizable
| NSWindowStyleMaskMiniaturizable;
NSWindow * win = [[NSWindow alloc] initWithContentRect:windowRect
styleMask:windowStyle
backing:NSBackingStoreBuffered
defer:NO];
win.title = @"Window Made in Code";
win.contentView.translatesAutoresizingMaskIntoConstraints = NO;
// add view
NSRect viewFrame = windowRect;
viewFrame.size.height = 80.0;
viewFrame.origin.y = 120.0;
NSView * view = [[MyView alloc] initWithFrame:viewFrame];
[win.contentView addSubview:view];
[view setNeedsDisplay:YES];
// add constraints
[view.leadingAnchor constraintEqualToAnchor:win.contentView.leadingAnchor].active = YES;
[view.trailingAnchor constraintEqualToAnchor:win.contentView.trailingAnchor].active = YES;
[view.topAnchor constraintEqualToAnchor:win.contentView.topAnchor].active = YES;
// note, the above also tried using layoutMargins of superview, same behavior
// show window
[win setIsVisible:YES];
[win center];
self.codeWindow = win;
[self.codeWindow makeKeyAndOrderFront:NSApp];
}
如果我不添加约束,一切都会正确绘制,但正如预期的那样,子视图不会随着 window.
调整大小当我添加约束时,超级视图(window 的 contentView) 的大小调整为高度 0,因此不会绘制任何内容。如果我省略顶部约束,这不会发生,但是水平约束会向后工作:而不是在 window 调整大小时调整子视图的大小,它们会阻止 Window contentView 水平调整大小;我仍然可以将 window 拖动得更大,但调试时发现内容视图框架宽度没有增加。
这是我也尝试使用 NSLayoutConstraint 工厂方法的替代代码方法;我在这里设置优先级,但没有不同的优先级纠正行为:
NSLayoutConstraint * leadingC = [NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:view.superview
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:0.0];
leadingC.priority = NSLayoutPriorityDragThatCannotResizeWindow;
NSLayoutConstraint * trailingC = [NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:view.superview
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:0.0];
trailingC.priority = NSLayoutPriorityDragThatCannotResizeWindow;
NSLayoutConstraint * topC = [NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:view.superview
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0];
[NSLayoutConstraint activateConstraints:@[leadingC, trailingC, topC]];
[view.superview addConstraints:self.constraints];
因为我尝试这几种不同的方法得到了同样糟糕的结果,所以我觉得我一定是完全遗漏了 NSLayoutConstraint 的某些东西,但我无法从教程或文档中弄清楚。我确实在运行时通过调试布局约束在 .xib 和代码创建的 windows 之间进行了比较,但无法从差异中重建我做错了什么,除了 .xib 超级视图具有 NSAutoresizingMaskLayoutConstraint 对象。
如果我注释掉 win.contentView.translatesAutoresizingMaskIntoConstraints = NO;
我确实会以编程方式调整大小行为,但这让我感到困惑 - 我认为当我们创建显式约束时我们应该将该标志设置为 NO?
感谢您就如何实现此功能提出任何建议!
当您选择加入约束时,您必须用约束完整地描述视图的大小。在这种情况下,您已经指定了工具栏的宽度,并设置了它的位置,但看起来您正试图用最初提供给视图的框架来固定高度。你还必须有一个约束来设置它的高度。
同时 translatesAutoresizingMaskIntoConstraints
描述了视图如何与其父视图相关,而不是与其子视图相关。所以你应该在工具栏视图上设置它,而不是 window 的 contentView。试试这个代码:
#import "AppDelegate.h"
@interface AppDelegate ()
@end
@interface MyView : NSView
@end
@implementation MyView
- (void)drawRect:(NSRect)dirtyRect
{
CGContextRef cgContext = [[NSGraphicsContext currentContext] CGContext];
CGContextSetFillColorWithColor(cgContext, [[NSColor yellowColor] CGColor]);
CGContextFillRect(cgContext, self.bounds);
}
@end
@implementation AppDelegate
{
NSWindowController *disjointController;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSRect windowRect = NSMakeRect(0.0, 0.0, 900.0, 200.0);
NSWindowStyleMask windowStyle = NSWindowStyleMaskTitled
| NSWindowStyleMaskClosable
| NSWindowStyleMaskResizable
| NSWindowStyleMaskMiniaturizable;
NSWindow * win = [[NSWindow alloc] initWithContentRect:windowRect
styleMask:windowStyle
backing:NSBackingStoreBuffered
defer:NO];
win.title = @"Window Made in Code";
// add view
NSView *view = [[MyView alloc] initWithFrame: windowRect];
view.translatesAutoresizingMaskIntoConstraints = NO;
view.layer.backgroundColor = [[NSColor yellowColor] CGColor];
[win.contentView addSubview: view];
// add constraints
[view.leadingAnchor constraintEqualToAnchor: win.contentView.leadingAnchor].active = YES;
[view.trailingAnchor constraintEqualToAnchor: win.contentView.trailingAnchor].active = YES;
[view.topAnchor constraintEqualToAnchor: win.contentView.topAnchor].active = YES;
[view.heightAnchor constraintEqualToConstant: 80].active = YES;
// show window
[win center];
disjointController = [[NSWindowController alloc] initWithWindow: win];
[win makeKeyAndOrderFront:NSApp];
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
- (BOOL)applicationSupportsSecureRestorableState:(NSApplication *)app {
return YES;
}
@end