使用 VFL 在 NSView 内部对齐 NSView
Aligning NSView inside NSView using VFL
我有一个 NSView 的子视图(比如 MainView),里面有 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")
}
}
Align Right
和 Center
工作正常,但 Align left
不工作。
此外,由于垂直居中对于所有外壳都是通用的,因此可以将其从开关外壳中取出吗?
几个问题:
您通常不会在 VFL 中显式列出父视图。相反,您使用垂直线 (|
) 字符。这个:
H:[superview]-(<=1)-[innerView]
并不意味着 innerView
的前沿小于 1 点 "after" 父视图的前沿。这意味着 innerView
的前沿在父视图的 尾随 边缘之后不到 1 点,这可能会将 innerView
置于其父视图的边界之外,这将导致它被剪掉了。
如果这些是您添加的影响 innerView
的唯一约束,那么您的布局不明确。不等式允许任何可能的值,并且系统没有可靠的方法来选择其中一个值而不是其他任何值。
您无法真正表达 VFL 中的居中。您可以将对齐标志传递给 constraintsWithVisualFormat(_:options:metrics:views:)
(如您所知),但是 a) 这并不是视觉格式语言本身的真正一部分,并且 b) 如果不创建一些伪造的,您就不能这样做,另一个方向上不需要的约束。也就是说,除非您还创建了一些伪造的水平约束,否则您不能使用对齐标志来垂直居中。 (反之亦然。)这是因为对齐标志仅适用于 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)
这将处理所有三种情况。
我有一个 NSView 的子视图(比如 MainView),里面有 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")
}
}
Align Right
和 Center
工作正常,但 Align left
不工作。
此外,由于垂直居中对于所有外壳都是通用的,因此可以将其从开关外壳中取出吗?
几个问题:
您通常不会在 VFL 中显式列出父视图。相反,您使用垂直线 (
|
) 字符。这个:H:[superview]-(<=1)-[innerView]
并不意味着
innerView
的前沿小于 1 点 "after" 父视图的前沿。这意味着innerView
的前沿在父视图的 尾随 边缘之后不到 1 点,这可能会将innerView
置于其父视图的边界之外,这将导致它被剪掉了。如果这些是您添加的影响
innerView
的唯一约束,那么您的布局不明确。不等式允许任何可能的值,并且系统没有可靠的方法来选择其中一个值而不是其他任何值。您无法真正表达 VFL 中的居中。您可以将对齐标志传递给
constraintsWithVisualFormat(_:options:metrics:views:)
(如您所知),但是 a) 这并不是视觉格式语言本身的真正一部分,并且 b) 如果不创建一些伪造的,您就不能这样做,另一个方向上不需要的约束。也就是说,除非您还创建了一些伪造的水平约束,否则您不能使用对齐标志来垂直居中。 (反之亦然。)这是因为对齐标志仅适用于 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)
这将处理所有三种情况。