NSScrollView mit automatischem Layout, dessen Größe erst nach dem ersten manuellen Ändern der Fenstergröße geändert wird

Ich habe eine programmgesteuerte OSX Cocoa-App (d. H. Nicht mit einer NIB / XIB), die ich mit dem automatischen Layout auslegen möchte. Beim ersten Anzeigen des Fensters tritt jedoch ein merkwürdiges Verhalten auf.

Mein Hauptinhalt ist ein NSView mit einer Sammlung von 100 NSButtons als Unteransichten, die vertikal angeordnet sind. Die Schaltflächen sind alle relativ zum NSView und untereinander eingeschränkt. Sowohl der NSView als auch alle NSButtons habentranslatesAutoresizingMaskIntoConstraints=NO einstellen. Ich halte den Code für die Inhaltsansicht für gut (d. H. Keine mehrdeutigen Layouts usw.), da die Schaltflächen wie erwartet angezeigt werden, wenn ich die Inhaltsansicht des Hauptfensters auf NSView stelle.

Wenn ich jedoch die contentView des Hauptfensters als NSScrollView und die documentView der NSScrollView als NSView einstelle, treten Anzeigeprobleme auf.

Bei der ersten Anzeige erhalte ich ein leeres Fenster - keine Bildlaufleisten, nichts:

Das NSScrollView hattranslatesAutoresizingMaskIntoConstraints=NO. Zu Debug-Zwecken habe ich auch die Hintergrundfarbe von NSScrollView auf Blau gesetzt, damit ich überprüfen kann, was wo angeordnet wird - aber nirgendwo wird Blau angezeigt.

Sobald ich jedoch die Größe des Fensters verändere, wird das Layout aktiviert und ich erhalte eine NSScrollView in voller Größe des Hauptfensters mit blauem Hintergrund und Bildlaufleisten wie erwartet:

Ich habe einige Referenzen gelesen, die darauf hindeuten, dass das Problem darin besteht, dass die ClipView, die Teil der NSScrollView ist, keine Einschränkungen aufweist. Auf dieser Basis habe ich versucht, eine Einschränkungsbindung einzurichten[NSScrollView contentView] zu[NSScrollView documentView] in vertikaler und horizontaler Richtung (bei konstanter 0 Multiplikator 1 links, rechts, oben und unten). Wenn ich das mache, ist die NSScrollView jetzt auf der ersten Anzeige sichtbar, aber sie hat die falsche Größe. Der Bildlauf scrollt nicht über die gesamte Höhe des internen Inhalts - der scrollbare Inhalt scrollt so, als hätte er die gleiche Größe wie das sichtbare Fenster. Zuletzt überlappt der Inhalt die Titelleiste des Fensters:

Sobald ich die Größe des Fensters verändere, werden die Einschränkungen aktiviert und das Fenster wird wie erwartet angezeigt (siehe den vorherigen Screenshot). Ich gehe davon aus, dass die zusätzlichen Einschränkungen nicht schaden, aber sie scheinen auch nichts hinzuzufügen.

Weitere verwirrende Dinge: Wenn ich die Schaltflächen ganz weglasse und nur eine leere NSView ohne Unteransichten als Inhaltsansicht verwende, bekomme ich beim Start wie erwartet ein volles blaues Fenster.

Also - was ist hier los? Es fühlt sich so an, als würde mir ein Anruf entgehen, um die Bewertung der Einschränkungen für die Schaltflächen zu erzwingen. Ist das der Fall oder ist hier noch etwas los?

Für Interessierte - hier ist mein Beispielcode. Es ist nicht Objective C - es ist Python - aber die Sprachbindung kann Python-Methodennamen in Objective C-Nachrichten konvertieren. Die Zuordnung zur nativen ObjectiveC-API sollte offensichtlich sein:

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

Antworten auf die Frage(3)

Ihre Antwort auf die Frage