NSScrollView与自动布局不调整大小,直到第一个手动窗口调整大小 [英] NSScrollView with auto layout not resizing until first manual window resize

查看:188
本文介绍了NSScrollView与自动布局不调整大小,直到第一个手动窗口调整大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个OSX Cocoa应用程序已经编程(即,不是一个NIB / XIB),我试图使用自动布局 - 但是我得到一些奇怪的行为,当窗口第一显示。



我的主要内容是一个NSView,它拥有100个NSButton的集合作为子视图,垂直布局。这些按钮都是相对于NSView和彼此约束的; NSView和所有的NSButtons都有 translatesAutoresizingMaskIntoConstraints = NO 设置。我相信内容视图的代码是好的(即没有模糊的布局等),因为如果我将主窗口的contentView设置为NSView,按钮显示为预期。



但是,如果我将主窗口的contentView设置为NSScrollView,并将NSScrollView的documentView设置为NSView,则会出现显示问题。



在第一次显示时,我得到一个空白窗口 - 没有滚动条,没有:





NSScrollView具有 translatesAutoresizingMaskIntoConstraints = NO 。为了调试的目的,我也设置NSScrollView的背景颜色为蓝色,这样我可以确认布局在哪里 - 但没有蓝色显示在任何地方。







ve读取一些参考,建议问题是缺乏对作为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.setHasHorizo​​ntalScroller_(True)
scrollview.setAutohidesScrollers_(True)
scrollview.setBorderType_(NSNoBorder)
scrollview.setTranslatesAutoresizingMaskIntoConstraints_(False)

scrollview.backgroundColor = NSColor.blueColor()

container = NSView.alloc()。init()
container.setTranslatesAutoresizingMaskIntoConstraints_(False)

buttons = [
NSButton.alloc b对于范围(0,100)
]

对于i,枚举中的按钮(按钮):
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()


解决方案

我已经找到了答案 - 但它似乎工作。



有一些Cocoa小部件不能很好地与autolayout - 特别是,我发现顶层的问题 NSWindow s和 NSTabViewItem s;我猜其他小部件也可能受到影响。基本上,这些是具有必须设置的顶级视图的容器小部件。如果包含小部件是NSScrollView(其本身将包含其他小部件),则容器小部件难以为包含滚动视图建立大小。



修复方法是为将要使用的视图重新启用 translatesAutoresizingMaskIntoConstraints 作为包含小部件。在提供的示例中,在第10行创建的对象 scroll_view 是包含窗口小部件;在第15行上对 setTranslatesAutoresizingMaskIntoConstraints 的调用的布尔值应该是 True ,而不是 False



这些问题在更新的OS / X版本中更好 - Mavericks没有问题 ,但它仍然有一个问题与 NSTabViewItem 。然而,它似乎没有任何损害,打开 translatesAutoresizingMaskIntoConstraints 在较新版本的OS X;所有你失去了100%自动布局解决方案的理论纯度。


I've got an OSX Cocoa app that has been built programatically (i.e., not with a NIB/XIB), which I'm trying to lay out using auto layout - but I'm getting some odd behaviour when the window first displays.

My main content is an NSView that holds has a collection of 100 NSButtons as subviews, laid out vertically. The buttons are all constrained relative to the NSView and each other; both the NSView and all the NSButtons have translatesAutoresizingMaskIntoConstraints=NO set. I believe the code for the content view is good (i.e., no ambiguous layouts, etc), because if I set the main window's contentView to the NSView, the buttons display as expected.

However, if I set the main window's contentView to be an NSScrollView, and set the documentView of the NSScrollView to be the NSView, I get display problems.

On first display, I get a blank window - no scroll bars, nothing:

The NSScrollView has translatesAutoresizingMaskIntoConstraints=NO. For debug purposes, I've also set the background colour of the NSScrollView to blue so that I can confirm what is being laid out where - but there's no blue shown anywhere.

But, as soon as I resize the window, the layout kicks in, and I get an NSScrollView the full size of the main window, with blue background, and scrollbars as expected:

I've read some references that suggest the problem is the lack of constraints on the clipView that is part of the NSScrollView. On that basis, I've tried setting up constraints binding [NSScrollView contentView] to [NSScrollView documentView] in the vertical and horizontal directions (with constant 0, multiplier 1, on the left, right, top and bottom). When I do this, the NSScrollView is now visible on first display, but it's the wrong size. The scroll doesn't scroll the full height of the internal content - the scrollable content scrolls as if it is the same size as the visible window. Lastly, the content overlaps the titlebar of the window:

Again, as soon as I resize the window, the constraints kick in, and the window displays as I'd expect (see the previous screenshot). So, I take it the extra constraints don't hurt, but they don't seem to be adding anything, either.

Further confusing matters - if I leave the buttons off altogether, and just use an empty NSView with no subviews as the content view, I get a full window of blue on startup, as I'd expect.

So - what's going on here? It feels like I'm missing a call to force the evaluation of constraints on the buttons; is that the case, or is something else going on here?

For those interested - here's my sample code. It's not Objective C - it's Python - but the language binding can convert Python method names into Objective C messages; the mapping to native ObjectiveC API should be obvious:

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()

解决方案

I've worked out an answer - I'm not entirely happy with it, but it seems to work.

There are certain Cocoa widgets that don't deal well with autolayout - in particular, I've found problems with top level NSWindows and NSTabViewItems; I'm guessing other widgets might also be affected. Essentially, these are "container" widgets that have a top level "view" that must be set. If the "contained" widget is an NSScrollView (which itself will contain other widgets), the "container" widget has difficulty establishing a size for the "contained" scroll view.

The fix is to re-enable translatesAutoresizingMaskIntoConstraints for the view that will be used as the "contained" widget. In the example provided, the object scroll_view created on line 10 is the "contained" widget; the boolean value of the call to setTranslatesAutoresizingMaskIntoConstraints on line 15 should be True, not False.

These problems get better with more recent versions of OS/X - Mavericks doesn't have a problem with NSWindow, but it still has a problem with NSTabViewItem. However, it doesn't seem to do any damage to turn on translatesAutoresizingMaskIntoConstraints on newer versions of OS X; all you're losing it the theoretical purity of a 100% autolayout solution.

这篇关于NSScrollView与自动布局不调整大小,直到第一个手动窗口调整大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆