Динамическое добавление ячеек в NSMatrix, выложенное с помощью Auto Layout, имеет странные эффекты; Зачем?

Я хочу создать группу переключателей, используя метод NSMatrix, который использует Interface Builder, но в коде. Матрица выложена с использованием Auto Layout. У меня это в основном работает, за исключением случаев, когда я добавляю новые опции во время выполнения.

В следующем примере, если несколько раз щелкнуть "Добавить элемент", все будет работать нормально, тогда матрица начнет выходить из окна в верхней части (по крайней мере, я думаю, что оно обрезается сверху). Если вы развернете это окно после добавления нескольких элементов, оно будет иметь одинаковую высоту, и все элементы будут обрезаны до высоты около одного пикселя, что очень нежелательно:)

В моей настоящей программе (не в этом тесте ниже) она работает в основном нормально, но если я динамически добавляю опцию, после определенного количества элементов (первоначально 5), опции будут обрезаться очень незначительно, выглядя слегка сжатыми или сжатыми. Добавление другого параметра отменяет это, пока не будет нажата следующая магическая цифра.

В чем дело? Я тестирую это на OS X Yosemite. Благодарю.

// 17 august 2015
import Cocoa

var keepAliveMainwin: NSWindow? = nil
var matrix: NSMatrix? = nil

class ButtonHandler : NSObject {
    @IBAction func onClicked(sender: AnyObject) {
        var lastRow = matrix!.numberOfRows
        matrix!.renewRows(lastRow + 1, columns: 1)
        var cell = matrix!.cellAtRow(lastRow, column: 0) as! NSButtonCell
        cell.title = "New Item"
        matrix!.sizeToCells()
    }
}

var buttonHandler: ButtonHandler = ButtonHandler()

func appLaunched() {
    var mainwin = NSWindow(
        contentRect: NSMakeRect(0, 0, 320, 240),
        styleMask: (NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask),
        backing: NSBackingStoreType.Buffered,
        defer: true)
    var contentView = mainwin.contentView as! NSView

    var prototype = NSButtonCell()
    prototype.setButtonType(NSButtonType.RadioButton)
    prototype.font = NSFont.systemFontOfSize(NSFont.systemFontSizeForControlSize(NSControlSize.RegularControlSize))

    matrix = NSMatrix(frame: NSZeroRect,
        mode: NSMatrixMode.RadioModeMatrix,
        prototype: prototype,
        numberOfRows: 0,
        numberOfColumns: 0)
    matrix!.allowsEmptySelection = false
    matrix!.selectionByRect = true
    matrix!.intercellSpacing = NSMakeSize(4, 2)
    matrix!.autorecalculatesCellSize = true
    matrix!.drawsBackground = false
    matrix!.drawsCellBackground = false
    matrix!.autosizesCells = true
    matrix!.translatesAutoresizingMaskIntoConstraints = false
    contentView.addSubview(matrix!)

    var button = NSButton(frame: NSZeroRect)
    button.title = "Append Item"
    button.setButtonType(NSButtonType.MomentaryPushInButton)
    button.bordered = true
    button.bezelStyle = NSBezelStyle.RoundedBezelStyle
    button.font = NSFont.systemFontOfSize(NSFont.systemFontSizeForControlSize(NSControlSize.RegularControlSize))
    button.translatesAutoresizingMaskIntoConstraints = false
    contentView.addSubview(button)

    button.target = buttonHandler
    button.action = "onClicked:"

    var views: [String: NSView]
    views = [
        "button":   button,
        "matrix":   matrix!,
    ]
    addConstraints(contentView, "V:|-[matrix]-[button]-|", views)
    addConstraints(contentView, "H:|-[matrix]-|", views)
    addConstraints(contentView, "H:|-[button]-|", views)

    mainwin.cascadeTopLeftFromPoint(NSMakePoint(20, 20))
    mainwin.makeKeyAndOrderFront(mainwin)
    keepAliveMainwin = mainwin
}

func addConstraints(view: NSView, constraint: String, views: [String: NSView]) {
    var constraints = NSLayoutConstraint.constraintsWithVisualFormat(
        constraint,
        options: NSLayoutFormatOptions(0),
        metrics: nil,
        views: views)
    view.addConstraints(constraints)
}

class appDelegate : NSObject, NSApplicationDelegate {
    func applicationDidFinishLaunching(note: NSNotification) {
        appLaunched()
    }

    func applicationShouldTerminateAfterLastWindowClosed(app: NSApplication) -> Bool {
        return true
    }
}

func main() {
    var app = NSApplication.sharedApplication()
    app.setActivationPolicy(NSApplicationActivationPolicy.Regular)
    // NSApplication.delegate is weak; if we don't use the temporary variable, the delegate will die before it's used
    var delegate = appDelegate()
    app.delegate = delegate
    app.run()
}

main()

1 ответ

Решение

Видимо, вам нужно пропустить вызов sizeToCells() после звонка renewRows(_:columns:), Я предполагаю, что он устанавливает размер кадра, который в большинстве случаев бесполезен при использовании автоматической разметки, но также очищает где-то "грязный" флаг, который говорит матрице, что он должен сделать недействительным свой собственный размер. Другими словами, матрица думает, что она уже выполнила то, что ей нужно было сделать.

Другие вопросы по тегам