我有一个OSX Cocoa应用程序,它是以编程方式构建的(即,不是使用NIB / XIB),我试图使用自动布局进行布局 - 但是我在窗口时遇到了一些奇怪的行为首先显示。
我的主要内容是一个NSView,其中包含100个NSButton作为子视图的集合,垂直排列。这些按钮都相对于NSView和彼此都受到约束; NSView和所有NSButton都设置了translatesAutoresizingMaskIntoConstraints=NO
。我相信内容视图的代码很好(即没有模糊的布局等),因为如果我将主窗口的contentView设置为NSView,按钮会按预期显示。
但是,如果我将主窗口的contentView设置为NSScrollView,并将NSScrollView的documentView设置为NSView,则会出现显示问题。
在第一次显示时,我得到一个空白窗口 - 没有滚动条,没有:
NSScrollView有translatesAutoresizingMaskIntoConstraints=NO
。出于调试目的,我还将NSScrollView的背景颜色设置为蓝色,以便我可以确认在哪里布局 - 但是在任何地方都没有显示蓝色。
但是,只要我调整窗口大小,布局就会启动,我会得到一个NSScrollView主窗口的完整大小,蓝色背景和滚动条按预期方式:
我读过一些引用,表明问题是对作为NSScrollView一部分的clipView缺乏约束。在此基础上,我尝试在垂直和水平方向上设置约束[NSScrollView contentView]
到[NSScrollView documentView]
的约束(在左侧,右侧,顶部和底部使用常数0,乘数1)。当我这样做时,NSScrollView现在在第一次显示时可见,但它的大小错误。滚动不会滚动内部内容的整个高度 - 可滚动内容会滚动,就好像它与可见窗口的大小相同。最后,内容与窗口的标题栏重叠:
同样,一旦我调整窗口大小,约束就会启动,窗口会显示为我所期望的(参见上一个屏幕截图)。所以,我认为额外的限制没有受到伤害,但它们似乎也没有添加任何东西。
进一步令人困惑的事情 - 如果我完全不使用按钮,只使用没有子视图的空NSView作为内容视图,我会在启动时获得完整的蓝色窗口,正如我所期望的那样。
那么 - 这里发生了什么?感觉我错过了一个强制评估按钮约束的调用;就是这种情况,或者是其他事情发生在这里?
对于那些感兴趣的人 - 这是我的示例代码。它不是Objective C - 它是Python - 但是语言绑定可以将Python方法名称转换为Objective C消息;原生ObjectiveC API的映射应该是显而易见的:
app = NSApplication.sharedApplication()
app.setActivationPolicy_(NSApplicationActivationPolicyRegular)
main_window = NSWindow.alloc().initWithContentRect_styleMask_backing_defer_(
NSMakeRect(100, 100, 640, 480),
NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask,
NSBackingStoreBuffered,
False)
scrollview = NSScrollView.alloc().init()
scrollview.setHasVerticalScroller_(True)
scrollview.setHasHorizontalScroller_(True)
scrollview.setAutohidesScrollers_(True)
scrollview.setBorderType_(NSNoBorder)
scrollview.setTranslatesAutoresizingMaskIntoConstraints_(False)
scrollview.backgroundColor = NSColor.blueColor()
container = NSView.alloc().init()
container.setTranslatesAutoresizingMaskIntoConstraints_(False)
buttons = [
NSButton.alloc().init()
for b in range(0, 100)
]
for i, button in enumerate(buttons):
button.setBezelStyle_(NSRoundedBezelStyle)
button.setButtonType_(NSMomentaryPushInButton)
button.setTitle_(get_NSString('Button %s' % i))
button.setTranslatesAutoresizingMaskIntoConstraints_(False)
container.addSubview_(button)
if i == 0:
container.addConstraint_(NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_(
button, NSLayoutAttributeTop,
NSLayoutRelationEqual,
container, NSLayoutAttributeTop,
1, 50,
))
else:
container.addConstraint_(NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_(
button, NSLayoutAttributeBottom,
NSLayoutRelationEqual,
buttons[i-1], NSLayoutAttributeBottom,
1, 50,
))
container.addConstraint_(NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_(
button, NSLayoutAttributeLeft,
NSLayoutRelationEqual,
container, NSLayoutAttributeLeft,
1, 50,
))
container.addConstraint_(NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_(
button, NSLayoutAttributeRight,
NSLayoutRelationEqual,
container, NSLayoutAttributeRight,
1, -50,
))
container.addConstraint_(NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_(
buttons[-1], NSLayoutAttributeBottom,
NSLayoutRelationEqual,
container, NSLayoutAttributeBottom,
1, -50,
))
scrollview.setDocumentView_(container)
main_window.setContentView_(scrollview)
main_window.makeKeyAndOrderFront_(None)
app.activateIgnoringOtherApps_(True)
app.run()
答案 0 :(得分:8)
我已经找到了答案 - 我对它并不完全满意,但似乎有效。
某些Cocoa小部件不能很好地处理自动布局 - 特别是,我发现顶级NSWindow
和NSTabViewItem
的问题;我猜其他小部件也可能受到影响。基本上,这些是具有必须设置的顶级“视图”的“容器”小部件。如果“包含”窗口小部件是NSScrollView(它本身将包含其他窗口小部件),则“容器”窗口小部件很难为“包含”滚动视图建立大小。
修复是重新启用 translatesAutoresizingMaskIntoConstraints
,用于将用作“包含”小部件的视图。在提供的示例中,在第10行创建的对象scroll_view
是“包含”小部件;第15行调用setTranslatesAutoresizingMaskIntoConstraints
的布尔值应为True
,而不是False
。
对于更新版本的OS / X,这些问题会变得更好 - Mavericks对NSWindow
没有问题,但它仍然存在NSTabViewItem
的问题。但是,在较新版本的OS X上打开translatesAutoresizingMaskIntoConstraints
似乎没有任何损害;所有你都失去了100%自动布局解决方案的理论纯度。
答案 1 :(得分:0)
真正的问题是你的一些控件正在修复视图的大小,从而修复了窗口的大小。例如,如果您只有一个视图,请在viewcontroller的视图中说view1,并且:
这将使您的窗口大小固定为300,因此无法调整大小。
答案 2 :(得分:0)
查看Apple的2012年开发者大会有关自动布局的视频,了解有关在代码中使用自动布局的信息。
只需在Interface Builder或代码中使用我在本视频教程中记录的方法:
How to use NSScrollView with Auto Layout
这是我在此视频中使用的方法:
窗口 - 设置委托和IBOutlet属性
ScrollView - 固定边缘,无边框,不画背景
documentView - 固定边0,然后是另一个尾部和底部,clipView≥0@ 499和clipView≤0@ 501,对于documentView的尾随和底部约束
水平堆栈视图中的标签和文本字段,垂直堆栈视图
垂直堆栈视图固定边缘默认,然后是另一个底部,底部≤默认值@ 499并且≥默认值@ 750
水平堆栈视图前导和尾随固定0
标签和文本字段将Y中心与水平堆栈视图对齐
文字字段顶部和底部,尾随2 @ 750,宽度≥100,高度≥22
后续水平堆栈视图前导和尾随固定,对齐文本字段引导