使用可视格式NSLayoutConstraints对中视图

时间:2013-11-16 16:07:57

标签: objective-c ios7 autolayout nslayoutconstraint

我正在尝试使用可视化格式语言来集中视图。

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

viewsNSDictionaryOfVariableBindings,其中包含_progressView

它不会将我的视图(宽度:300)置于self.view(宽度:768)内。它将左边的边距与8像素边距对齐,好像我只写了@"H:|-[_progressView(300)"

是使用以下内容实现视图居中的唯一方法吗?

[self.view addConstraint:[NSLayoutConstraint constraintWithItem:_progressView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual
                                                             toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];

由于

3 个答案:

答案 0 :(得分:34)

此格式字符串

@"H:|-[_progressView(300)]-|"

不会告诉AutoLayout居中progressView。相反,它表示progressView应该是300宽,并且在超视图边缘的任一侧都有一个系统定义的标准边距。显然这不能满足,因此Auto Layout会删除一些约束(您可能会在控制台上获得一些日志)。在你的案例中删除的约束可能是右边的边距。

要真正将视图置于其超级视图中心,您必须使用详细约束方法而不是可视字符串格式,正如您已经想到的那样。但是,你可以很容易地把它放到这样一个很好的类别中:

@interface UIView (MyLayout)
- (void)centerHorizontallyInSuperview;
@end

@implementation UIView (MyLayout)
- (void)centerHorizontallyInSuperview {
    NSLayoutConstraint *c;
    c = [NSLayoutConstraint constraintWithItem:self
                                     attribute:NSLayoutAttributeCenterX
                                     relatedBy:NSLayoutRelationEqual                                                             
                                        toItem:self.superview
                                     attribute:NSLayoutAttributeCenterX 
                                    multiplier:1 
                                      constant:0];
    [self.superview addConstraint:c];
}
@end

答案 1 :(得分:17)

三种方法:

  1. 您可以根据DrummerB的建议将约束添加到方法或类别中。

    你也是有效的iOS 9,可以使用更新,更简洁的语法,使用锚点并使用activateConstraints

    [NSLayoutConstraint activateConstraints:@[
        [centerView.centerXAnchor constraintEqualToAnchor:view.centerXAnchor],
        ...
    ]];
    

    或者在Swift 3中:

    NSLayoutConstraint.activate([
        centerView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
        ...
    ])
    
  2. 您可以使用UILayoutGuide个对象:

    UILayoutGuide *leftGuide = [[UILayoutGuide alloc] init];
    [view addLayoutGuide:leftGuide];
    UILayoutGuide *rightGuide = [[UILayoutGuide alloc] init];
    [view addLayoutGuide:rightGuide];
    

    并用VFL将它们定义为彼此相等:

    H:|[leftGuide][_progressView(==300)][rightGuide(==leftGuide)]|
    

    如果你不能使用布局指南(例如你需要支持9.0之前的iOS版本,你想在IB中创建它等)你可以使用不可见的UIView对象(alpha为零)或以非常相似的方式的背景颜色。只需将这些“spacer”视图添加到视图层次结构中,使用上面的水平约束,但只需配置视图就可以看不到它们。

    这种技术是一种解决“视图中心”问题的麻烦方法,但如果您想要均匀地分隔十几个视图并且不能使用{{1 }} 由于某些原因。您可以使用所需的UIStackView个(或不可见的UILayoutGuide)个对象来实现所需的效果。

  3. 为了完整起见,我应该指出,如https://stackoverflow.com/a/14917695/1271826中所述,使用UIView / options的{​​{1}}可以达到效果。但我承认我发现它不必要地混淆了。

  4. 就个人而言,我认为第一种方法对您的场景最有意义。第二种方法在尝试均匀分布一堆控件时很有用,但对于这种简单的场景来说太笨拙了。第三种方法是求知欲,但我不会在任何实际应用中提出建议。

答案 2 :(得分:7)

对于那些需要它的人,@ DrummerB的ObjC类别作为Swift扩展:

extension UIView {

    func centerInSuperview() {
        self.centerHorizontallyInSuperview()
        self.centerVerticallyInSuperview()
    }

    func centerHorizontallyInSuperview(){
        let c: NSLayoutConstraint = NSLayoutConstraint(item: self, attribute: .CenterX, relatedBy: .Equal, toItem: self.superview, attribute: .CenterX, multiplier: 1, constant: 0)
        self.superview?.addConstraint(c)
    }

    func centerVerticallyInSuperview(){
        let c: NSLayoutConstraint = NSLayoutConstraint(item: self, attribute: .CenterY, relatedBy: .Equal, toItem: self.superview, attribute: .CenterY, multiplier: 1, constant: 0)
        self.superview?.addConstraint(c)
    }

}