使用 VisualFormat 语言将视图居中显示在其视图中

我刚开始学习 iOS 的自动布局,并看了一下可视化格式语言。

除了一件事: 我只是不能让一个视图在它的超级视图中居中。
VFL 可以做到这一点吗? 还是我需要自己手动创建一个约束?

88581 次浏览

我知道这不是你想要的,但你当然可以计算边距,并使用它们来创建可视化格式的字符串;)

无论如何,不。不幸的是,不可能做到这一点’自动’与 VFL-至少现在还没有。

目前,不,看起来不可能使用 只有 VFL 在 Superview 中居中显示一个视图。然而,使用单个 VFL 字符串和单个额外约束(每个轴)来实现这一点并不困难:

"|-(>=20)-[view]-(>=20)-|"

[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:view.superview
attribute:NSLayoutAttributeCenterX
multiplier:1.f constant:0.f];

有人会认为你可以简单地做到这一点(这就是我最初看到这个问题时的想法和尝试) :

[NSLayoutConstraint constraintsWithVisualFormat:@"|-(>=20)-[view(==200)]-(>=20)-|"
options: NSLayoutFormatAlignAllCenterX | NSLayoutFormatAlignAllCenterY
metrics:nil
views:@{@"view" : view}];

我尝试了上面的许多不同的变化,试图弯曲它到我的意愿,但这似乎不适用于超视图,即使显式有两个单独的 VFL 字符串的两个轴(H:|V:)。然后,我开始尝试精确地隔离选项 应用于 VFL 的时间。它们似乎适用于 VFL 中的超级视图,并且只适用于 VFL 字符串中提到的任何显式视图(在某些情况下令人失望)。

我希望在未来苹果增加了一些新的选项,让 VFL 选项考虑到超视图,即使这样做只有当只有一个单一的显式视图除了在 VFL 中的超视图。另一个解决方案可以是传递到 VFL 中的另一个选项,其内容类似于: NSLayoutFormatOptionIncludeSuperview

不用说,我学到了很多关于 VFL 试图回答这个问题。

是的,使用可视化格式语言可以将视图放在它的视图中心。无论是纵向还是横向。下面是演示:

Https://github.com/evgenyneu/center-vfl

我认为最好手动创建约束。

[superview addConstraint:
[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0]];
[superview addConstraint:
[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeCenterY
multiplier:1
constant:0]];

现在我们可以使用 NSLayoutAnchor以编程方式定义 AutoLayout:

(可在 iOS 9.0及更高版本中使用)

view.centerXAnchor.constraint(equalTo: superview.centerXAnchor).isActive = true
view.centerYAnchor.constraint(equalTo: superview.centerYAnchor).isActive = true

我建议使用 SnapKit,它是一种 DSL,可以使 iOS 和 macOS 上的自动布局变得简单。

view.snp.makeConstraints({ $0.center.equalToSuperview() })

你可以很容易地在 Interface Builder 中做到这一点,而不是使用 VFL。在 Main Storyboard 中,ctrl + 单击要居中的视图。拖动到 Superview (同时保持 ctrl)并选择“ Center X”或“ Center Y”。不需要代码。

必须做的是在字典中声明 superview。使用 @{@"super": view.superview};代替使用 |

NSLayoutFormatAlignAllCenterX为垂直和 NSLayoutFormatAlignAllCenterY为水平作为选项。

完全有可能做到这样:

[NSLayoutConstraint constraintsWithVisualFormat:@"H:[view]-(<=1)-[subview]"
options:NSLayoutFormatAlignAllCenterY
metrics:nil
views:NSDictionaryOfVariableBindings(view, subview)];

这是从这里学到的。 上面的代码显然由 Y 中心查看。

Swift3:

        NSLayoutConstraint.constraints(withVisualFormat: "H:[view]-(<=1)-[subview]",
options: .alignAllCenterY,
metrics: nil,
views: ["view":self, "subview":_spinnerView])

您可以使用额外的视图。

NSDictionary *formats =
@{
@"H:|[centerXView]|": @0,
@"V:|[centerYView]|": @0,
@"H:[centerYView(0)]-(>=0)-[yourView]": @(NSLayoutFormatAlignAllCenterY),
@"V:[centerXView(0)]-(>=0)-[yourView]": @(NSLayoutFormatAlignAllCenterX),
};
NSDictionary *views = @{
@"centerXView": centerXView,
@"centerYView": centerYView,
@"yourView": yourView,
};
^(NSString *format, NSNumber *options, BOOL *stop) {
[superview addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:format
options:options.integerValue
metrics:nil
views:views]];
}];

如果你想它整洁,那么 centerXView.hidden = centerYView.hidden = YES;

PS: 我不确定我能把这些额外的视图称为“占位符”,因为英语是我的第二语言。如果有人能告诉我,我将不胜感激。

对于那些来这里寻找基于 Interface Builder的解决方案的人(Google 在这里引导我) ,只需要添加常量宽度/高度约束,并选择 subview-> 控件拖动到它的 superview-> 选择“在 superview 中垂直/水平居中”。

只需要说,你可以用这个代替约束:

child.center = [parent convertPoint:parent.center fromView:parent.superview];

@ igor-muzyka@/strong > Swift 2回答:

NSLayoutConstraint.constraintsWithVisualFormat("H:[view]-(<=1)-[subview]",
options: .AlignAllCenterY,
metrics: nil,
views: ["view":view, "subview":subview])

添加以下代码,并将按钮放在屏幕中央。

[self.view addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:@"H:|-[button]-|"
options:NSLayoutFormatAlignAllCenterY
metrics:0
views:views]];


[self.view addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:@"V:|-[button]-|"
options:NSLayoutFormatAlignAllCenterX
metrics:0
views:views]];

感谢@Evgenii 的回答,我在大意中创建了一个完整的例子:

用自定义高度将红色方块垂直居中

Https://gist.github.com/yallenh/9fc2104b719742ae51384ed95dcaf626

您可以通过使用 VFL (这不是很直观)或手动使用约束来垂直居中视图。 顺便说一下,在 VFL 中,我不能把中心和身高结合在一起,比如:

"H:[subView]-(<=1)-[followIcon(==customHeight)]"

在当前的解决方案中,VFL 约束是单独添加的。

这就是我的方法

//create a 100*100 rect in the center of superView
var consts = NSLayoutConstraint.constraints(withVisualFormat: "H:|-space-[myView]-space-|", options: [], metrics:["space":view.bounds.width/2-50], views:["myView":myView])


consts += NSLayoutConstraint.constraints(withVisualFormat: "V:|-space-[myView]-space-|", options: [], metrics: ["space":view.bounds.height/2-50], views: ["myView":myView])