Выравнивание NSView внутри NSView с использованием VFL

У меня есть Subview(скажем, MainView) NSView, с NSTextField внутри него.

Примечание: этот код основан на этом github.repo

MainView назначил инициализатор следующим образом

init(title : String, layout :NSLayoutAttribute) {
    innerView = self.createTextField(title)//Text field with stringValue = title
    mainView.addSubview(innerView)
    createViewConstrants(innerView, layout: layout)
}

макет может быть Left, Right или же CenterX,
(Внутренний TextView всегда будет вертикально по центру, может меняться только горизонтальное выравнивание)


Следующая функция создает ограничение для цели

func createViewConstrants(view : NSView, layout :NSLayoutAttribute) {

    let viewMap = ["innerView" : view, "superview" : mainView]
    var constraints :[AnyObject]!

    switch layout {
    case .Left:
        println("Left")
        constraints = NSLayoutConstraint.constraintsWithVisualFormat(
            "H:[superview]-(<=1)-[innerView]",
            options: NSLayoutFormatOptions.AlignAllCenterY,
            metrics: nil,
            views: viewMap)
        mainView.addConstraints(constraints)

    case .Right:
        println("Right")
        constraints = NSLayoutConstraint.constraintsWithVisualFormat(
            "H:[superview]-(<=1)-[innerView]-|",
            options: NSLayoutFormatOptions.AlignAllCenterY,
            metrics: nil,
            views: viewMap)
        mainView.addConstraints(constraints)

    case .CenterX:
        println("Center")

        constraints = NSLayoutConstraint.constraintsWithVisualFormat(
            "V:[superview]-(<=1)-[innerView]",
            options: NSLayoutFormatOptions.AlignAllCenterX,
            metrics: nil,
            views: viewMap)
        mainView.addConstraints(constraints)

        constraints = NSLayoutConstraint.constraintsWithVisualFormat(
            "H:[superview]-(<=1)-[innerView]",
            options: NSLayoutFormatOptions.AlignAllCenterY,
            metrics: nil,
            views: viewMap)
        mainView.addConstraints(constraints)

    default:
        fatalError("Invalid layout")

    }
}

выравнивать Right а также Center работают нормально, но Align left не работает.

Кроме того, поскольку вертикальное центрирование является общим для всех случаев, можно ли его извлечь из корпуса переключателя?

1 ответ

Решение

Несколько вопросов:

  1. Обычно вы не перечисляете суперпредставление явно в VFL. Скорее вы используете вертикальную линию (|) персонаж. Это:

    H:[superview]-(<=1)-[innerView]
    

    не значит что innerViewПередний фронт менее чем на 1 балл "после" переднего края суперпредставления. Это означает, что innerViewпередний край составляет менее 1 пункта после заднего края суперпредставления, что может поставить innerView за пределами его суперпредставления, что заставило бы его обрезаться.

  2. Если это единственные ограничения, которые вы добавляете, которые влияют на innerViewТогда ваш макет неоднозначен. Неравенство допускает любое из возможных значений, и у системы нет надежного способа выбора одного из этих значений над любым другим.

  3. Вы не можете выразить центрирование в VFL. Вы можете передать флаг выравнивания constraintsWithVisualFormat(_:options:metrics:views:) (как вы знаете), но а) это на самом деле не является частью языка визуального формата как такового, и б) вы не можете сделать это, не создавая поддельных, нежелательных ограничений в другой ориентации. То есть вы не можете использовать флаг выравнивания, чтобы центрировать вещи по вертикали, если вы также не создадите фиктивные горизонтальные ограничения. (И наоборот.) Это потому, что флаги выравнивания применяются только к представлениям, перечисленным в строке VFL, а строка VFL всегда подразумевает ограничения.

  4. Почему вы настаиваете на использовании VFL? Если вы используете init(item:attribute:relatedBy:toItem:attribute:multiplier:constant:)Вы можете просто пройти вдоль layout параметр, который получает ваш метод. Там не было бы необходимости в switch с несколькими случаями. Вы бы просто сделали:

    var constraint = NSLayoutConstraint(item: innerView,
                                   attribute: layout,
                                   relatedBy: .Equal,
                                      toItem: mainView,
                                   attribute: layout
                                  multiplier: 1,
                                    constant: 0)
    mainView.addConstraint(constraint)
    constraint = NSLayoutConstraint(item: innerView,
                               attribute: .CenterY,
                               relatedBy: .Equal,
                                  toItem: mainView,
                               attribute: .CenterY
                              multiplier: 1,
                                constant: 0)
    mainView.addConstraint(constraint)
    

    Это будет обрабатывать все три случая.

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