Выравнивание 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 ответ
Несколько вопросов:
Обычно вы не перечисляете суперпредставление явно в VFL. Скорее вы используете вертикальную линию (
|
) персонаж. Это:H:[superview]-(<=1)-[innerView]
не значит что
innerView
Передний фронт менее чем на 1 балл "после" переднего края суперпредставления. Это означает, чтоinnerView
передний край составляет менее 1 пункта после заднего края суперпредставления, что может поставитьinnerView
за пределами его суперпредставления, что заставило бы его обрезаться.Если это единственные ограничения, которые вы добавляете, которые влияют на
innerView
Тогда ваш макет неоднозначен. Неравенство допускает любое из возможных значений, и у системы нет надежного способа выбора одного из этих значений над любым другим.Вы не можете выразить центрирование в VFL. Вы можете передать флаг выравнивания
constraintsWithVisualFormat(_:options:metrics:views:)
(как вы знаете), но а) это на самом деле не является частью языка визуального формата как такового, и б) вы не можете сделать это, не создавая поддельных, нежелательных ограничений в другой ориентации. То есть вы не можете использовать флаг выравнивания, чтобы центрировать вещи по вертикали, если вы также не создадите фиктивные горизонтальные ограничения. (И наоборот.) Это потому, что флаги выравнивания применяются только к представлениям, перечисленным в строке VFL, а строка VFL всегда подразумевает ограничения.Почему вы настаиваете на использовании 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)
Это будет обрабатывать все три случая.