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

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

问题描述

我已经得到了已通过编程建立了一个OSX可可应用程序(即不带NIB / XIB),我正在努力奠定了使用自动布局 - 但我发现了一些奇怪的行为时,窗口首先显示。

我的主要内容是保存有100个NSButtons作为子视图的集合一个的NSView,垂直布局。这些按钮都制约相对的NSView和对方;双方的NSView和所有NSButtons有 translatesAutoresizingMaskIntoConstraints = NO 集。我相信,code的内容的看法是不错的(即不暧昧布局,等等),因为如果我的主窗口的内容查看设置为的NSView,按钮显示为预期。

不过,如果我设置主窗口的内容查看是一个NSScrollView,并设置NSScrollView的documentView是的NSView,我得到的显示问题。

在第一显示器,我得到了一个空白的窗口 - 没有滚动条,没有什么:

该NSScrollView有 translatesAutoresizingMaskIntoConstraints = NO 。为了调试,我还设置了NSScrollView的背景颜色为蓝色,这样我可以证实的是什么奠定了在那里 - 但是没有任何地方显示蓝色

不过,只要我调整窗口的大小,布局踢,我也得到一个NSScrollView主窗口的全尺寸,与蓝色的背景和滚动预期:

我读过一些参考的建议的问题是缺乏上是NSScrollView的一部分clipView限制。在此基础上,我试过设置约束结合 [NSScrollView内容查看] [NSScrollView documentView] 垂直和水平方向(与常数0,乘法器1,在左侧,右侧,顶部和底部)。当我做到这一点,NSScrollView现在是第一显示器上显示,但它是错误的大小。滚动不滚动的内部内容的整个高度 - 滚动内容滚动,就好像它是大小与可见的窗口相同。最后,内容重叠窗口的工具栏:

此外,只要我调整窗口的大小,约束踢,窗口显示为我期望(见previous截图)。所以,我把它额外的约束并不伤害,但他们似乎并不需要添加任何,无论是。

另外混乱的问题 - 如果我离开的按钮完全关闭,只是使用空的NSView没有子视图的内容来看,我得到的蓝色窗口全面启动时,因为我期望

所以 - 这是怎么回事呢?这感觉就像我失去了一个电话给力上的按钮约束的评价;是的情况下,或者是别的东西会在这里?

对于那些有兴趣 - 这里是我的样品code。这不是目标C - 这是Python的 - 但语言绑定可以Python的方法名转换成Objective C的消息;映射到本地ObjectiveC API应该是显而易见的:

 应用程序= NSApplication.sharedApplication()
app.setActivati​​onPolicy_(NSApplicationActivati​​onPolicyRegular)main_window = NSWindow.alloc()。initWithContentRect_styleMask_backing_defer_(
    NSMakeRect(100,100,640,480),
    NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask,
    NSBackingStoreBuffered,
    假)滚动型= NSScrollView.alloc()的init()
scrollview.setHasVerticalScroller_(真)
scrollview.setHasHorizo​​ntalScroller_(真)
scrollview.setAutohidesScrollers_(真)
scrollview.setBorderType_(NSNoBorder)
scrollview.setTranslatesAutoresizingMaskIntoConstraints_(假)scrollview.backgroundColor = NSColor.blueColor()容器= NSView.alloc()的init()
container.setTranslatesAutoresizingMaskIntoConstraints_(假)按钮= [
    NSButton.alloc()的init()
    为b在范围(0,100)
]对于我,按钮历数(按钮):
    button.setBezelStyle_(NSRoundedBezelStyle)
    button.setButtonType_(NSMomentaryPushInButton)
    button.setTitle_(get_NSString('按钮%s'的%I))
    button.setTranslatesAutoresizingMaskIntoConstraints_(假)    container.addSubview_(按钮)    如果我== 0:
        container.addConstraint_(NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_(
            按钮,NSLayoutAttributeTop,
            NSLayoutRelationEqual,
            集装箱,NSLayoutAttributeTop,
            1,50,
        ))
    其他:
        container.addConstraint_(NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_(
            按钮,NSLayoutAttributeBottom,
            NSLayoutRelationEqual,
            键[Ⅰ-1],NSLayoutAttributeBottom,
            1,50,
        ))    container.addConstraint_(NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_(
        按钮,NSLayoutAttributeLeft,
        NSLayoutRelationEqual,
        集装箱,NSLayoutAttributeLeft,
        1,50,
    ))    container.addConstraint_(NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_(
        按钮,NSLayoutAttributeRight,
        NSLayoutRelationEqual,
        集装箱,NSLayoutAttributeRight,
        1,-50,
    ))container.addConstraint_(NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_(
    按钮[-1],NSLayoutAttributeBottom,
    NSLayoutRelationEqual,
    集装箱,NSLayoutAttributeBottom,
    1,-50,
))scrollview.setDocumentView_(集装箱)main_window.setContentView_(滚动视图)main_window.makeKeyAndOrderFront_(无)app.activateIgnoringOtherApps_(真)
app.run()


解决方案

我已经制定了一个答案 - 我不与它完全满意,但它似乎工作。

有一定的可可小部件不自动布局很好地处理 - 尤其是,我发现与顶级的问题 NSWindow NSTabViewItem S;我猜的其他部件也可能受到影响。从本质上讲,这些都是容器小部件有一个顶层的查看,必须设定。如果载窗口小部件是一个NSScrollView(它本身包含其他widget),容器窗口小部件有困难建立一个大小为载滚动视图。

解决方法是的重新启用 translatesAutoresizingMaskIntoConstraints 为将要用作载插件的视图。在中,对象 scroll_view 第10行创建提供的例子就是载窗口小部件;呼叫到 setTranslatesAutoresizingMaskIntoConstraints 布尔值第15行应该是,而不是

这些问题得到更多最新版本的OS / X的更好 - 小牛没有与 NSWindow 的一个问题,但它仍然有<$ C $问题C> 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天全站免登陆