使用Visual Format Language在其超级视图中居中


160

我刚刚开始学习iOS的AutoLayout,并了解了Visual Format Language。

除了一件事,一切都很好:我只是无法将视图置于其超级视图的中心。
VFL是否可以实现此功能,还是需要我自己手动创建约束?

Answers:


232

当前,不,看起来使用VFL 不可能在超级视图中居中显示视图。但是,使用单个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}];

我尝试了上述方法的许多不同变体,以使其符合我的意愿,但这似乎不适用于超级视图,即使为两个轴(H:|V:)明确具有两个单独的VFL字符串也是如此。然后,我开始尝试确切地将选项何时确实应用到VFL上。他们似乎并不适用于VFL的上海华盈,仅适用于(在某些情况下,令人失望的),它们在VFL字符串提到任何明确的意见。

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

不用说,我了解了很多有关VFL试图回答这个问题的知识。


2
谢谢您的详细回答。但是,我使用VFL的唯一原因是摆脱了这些丑陋的约束。太糟糕了,Apple还不支持此功能...
Christian Schnorr 2012年

@larsacus您能否评论以下答案为何起作用?让我感到难过。
Matt G

8
叶夫根尼(Evgeny)的答案之所以行之有效|[superview]是因为自动布局引擎将和视为独立的内部实体,即使它们表示相同的语义对象。通过使用[superview],自动布局会将Superview对象包含在其对齐度量标准中(在github链接中,他的答案是NSLayoutFormatAlignAllCenterY/ X度量标准)。
larsacus 2014年

@larsacus太好了,谢谢!
Matt G

我们是否知道该限制是否仍然适用于当前iOS 7.x附带的VFL版本?
Drux

138

是的,可以使用Visual Format Language在其超级视图中居中视图。垂直和水平方向。这是演示:

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


15
这太棒了,您认为您可以对此进行扩展并解释它为何有效吗?
tapi

3
我最终利用了更接近标记答案的内容,但为您的github附件+1了
Rembrandt Q. Einstein

4
@Dan如果它对您不起作用,则可能还需要对宽度和高度设置约束。VFL的宽度是这样的:@“ [label(== 200)]”,高度是这样的:@“ V:[label(== 200)]”
Jonathan Zhan

1
为什么结果来自| 和[superview]不同?这是应该引起人们注意的事情,还是正在发生而我只是不遵循的事情?
Matt G

3
无法解析约束格式:选项掩盖了所需视图,使其在水平边缘对齐,这对于水平布局也是不允许的。H:[superview]-(<= 1)-[label1]
抓手2014年

82

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

[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() })

1
在我的上下文中效果最佳-尽管没有VFL。
Brainray 2014年

它给了我一个警告:Warning once only: Detected a case where constraints ambiguously suggest a height of zero for a tableview cell's content view. We're considering the collapse unintentional and using standard height instead.
Tapas Pal

10

绝对有可能做到这一点:

[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])

7

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

[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]];

1

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

反正不行 不幸的是,使用VFL无法“自动”执行此操作-至少现在还没有。


好了,您可以使用NSString stringWithFormat:在运行时动态构建VFL字符串。
TRVD1707 2015年


0

必须要做的是应该在字典中声明超级视图。使用而不是|使用@{@"super": view.superview};

并可NSLayoutFormatAlignAllCenterX选择垂直和NSLayoutFormatAlignAllCenterY水平。


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


这里缺少一些东西。您如何在视图声明下调用该块?它不是您所说的法律法规
ishahak

0

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


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])


-1

Swift 2中的@ igor-muzyka答案:

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

-3

除了使用VFL,您还可以在Interface Builder中轻松地执行此操作。在主情节提要中,按住Ctrl键并单击要居中的视图。拖动到超级视图(按住ctrl键),然后选择“中心X”或“中心Y”。无需代码。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.