161

我刚开始学习 AutoLayout for iOS 并查看了 Visual Format Language。

这一切都很好,除了一件事:我只是无法在其超级视图中获得中心视图。
VFL 可以做到这一点,还是我需要自己手动创建约束?

4

14 回答 14

232

目前,不,看起来不可能使用VFL 在超级视图中居中。但是,使用单个 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 字符串中提到的任何显式视图(在某些情况下令人失望)。

我希望将来Apple添加某种新选项以使VFL选项考虑到superview,即使仅在VFL中除了superview之外只有一个显式视图时才这样做。另一种解决方案可能是传递到 VFL 中的另一个选项,该选项类似于:NSLayoutFormatOptionIncludeSuperview.

不用说,我在尝试回答这个问题时学到了很多关于 VFL 的知识。

于 2012-10-30T21:44:09.160 回答
139

是的,可以使用 Visual Format Language 将视图置于其父视图的中心。垂直和水平。这是演示:

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

于 2013-02-17T03:31:24.300 回答
83

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

[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() })
于 2013-11-08T09:10:14.237 回答
10

绝对有可能做到这一点:

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

从这里学到了这一点。 上面的代码显然是以 Y 为中心的子视图。

斯威夫特3:

        NSLayoutConstraint.constraints(withVisualFormat: "H:[view]-(<=1)-[subview]",
                                       options: .alignAllCenterY,
                                                       metrics: nil,
                                                       views: ["view":self, "subview":_spinnerView])
于 2015-01-31T22:14:25.977 回答
8

添加下面的代码并将您的按钮放在屏幕的中心。绝对有可能。

[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]];
于 2016-09-13T13:08:41.313 回答
1

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

无论如何,没有。不幸的是,VFL 不可能“自动”地做到这一点——至少现在还没有。

于 2012-10-29T09:12:55.510 回答
1

感谢@Evgenii 的回答,我在要点中创建了一个完整的示例:

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

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

您可以通过使用 VFL(这不是很直观)或手动使用约束来垂直居中视图。顺便说一句,我不能在 VFL 中将 centerY 和 height 结合在一起,例如:

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

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

于 2017-07-05T07:39:38.337 回答
0

要做的是在字典中声明superview。而不是使用|你使用@{@"super": view.superview};.

并且NSLayoutFormatAlignAllCenterX对于垂直和NSLayoutFormatAlignAllCenterY水平作为选项。

于 2014-11-12T11:58:01.063 回答
0

您可以使用额外的视图。

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:我不确定我是否可以将额外的视图称为“占位符”,因为英语是我的第二语言。如果有人能告诉我,将不胜感激。

于 2015-03-21T13:58:08.937 回答
0

对于那些来这里寻求Interface Builder基于解决方案的人(谷歌在这里引导我),只需添加 const 宽度/高度约束,然后选择子视图 - >控制拖动到它的超级视图 - >选择“在超级视图中垂直/水平居中”。

于 2015-05-12T06:54:24.497 回答
0

@igor-muzyka在Swift 2中的回答:

NSLayoutConstraint.constraintsWithVisualFormat("H:[view]-(<=1)-[subview]", 
                                               options: .AlignAllCenterY,
                                               metrics: nil,
                                               views: ["view":view, "subview":subview])
于 2016-03-27T02:12:26.100 回答
0

这是我的方法

//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])
于 2019-12-25T03:44:48.500 回答
-1

只需要说,你可以使用它而不是约束:

child.center = [parent convertPoint:parent.center fromView:parent.superview];
于 2016-02-25T06:50:58.877 回答
-3

您可以在界面生成器中轻松完成此操作,而不是使用 VFL。在主情节提要中,按住 ctrl+单击要居中的视图。拖动到超级视图(按住 ctrl)并选择“Center X”或“Center Y”。无需代码。

于 2014-09-10T14:49:23.940 回答