以编程方式使用自动布局约束在视图中垂直对齐中间的子视图

Posted

技术标签:

【中文标题】以编程方式使用自动布局约束在视图中垂直对齐中间的子视图【英文标题】:Subview vertical align middle in view with auto layout constraints programmatically 【发布时间】:2014-11-12 08:27:01 【问题描述】:

我需要在视图中定位子视图垂直对齐中间,而无需以编程方式使用约束对顶部值 150 进行硬编码。我希望实现以下目标:

以下是我目前的代码,请指教。

import UIKit

class MainViewController: UIViewController 
 var viewInner:UIView = UIView()
    var viewOuter:UIView = UIView()


    override func viewDidLoad() 
        super.viewDidLoad()

        viewInner.backgroundColor = UIColor.redColor()
        viewOuter.backgroundColor = UIColor.purpleColor()
        viewOuter.frame = CGRectMake(100, 100, 400, 400)

        viewInner.setTranslatesAutoresizingMaskIntoConstraints(false)

        let viewsDictionary = ["viewInner":viewInner]

        viewOuter.addSubview(viewInner)
        self.view.addSubview(viewOuter)

        //Add Constraint

        var constOuterH = NSLayoutConstraint.constraintsWithVisualFormat("H:|-10-[viewInner(>=200)]-10-|", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDictionary)
        var constOuterV = NSLayoutConstraint.constraintsWithVisualFormat("V:|-150-[viewInner(100)]", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDictionary)

        viewOuter.addConstraints(constOuterH)
        viewOuter.addConstraints(constOuterV)
    

【问题讨论】:

如果你想让它居中但总是让顶部有一个固定的偏移量,你真的只是想要一个固定的顶部和底部值而不是真正的居中对齐吗? 我希望 viewInner 的高度始终为 100px,viewOuter 的高度可以更改为任何值。不需要固定顶部。 viewInner.frame = CGRectMake(0, 0, viewOuter.frame.size.width - 20, 100); viewInner.center = CGPointMake(200, 200);并删除 constOuterH 和 constOuterV。 如果中心总是固定的,什么会导致这个视图的大小发生变化? @Acey 似乎 kaneyip 想要为外部视图高度设置动画,但保持 innerView 始终以外部视图为中心。也许他正在尝试创建一个登录表单? :) 【参考方案1】:

需要使用非可视化格式化方式添加约束:

[self.view addConstraint:[NSlayoutConstraint constraintWithItem:self.viewOuter attribute:NSLayoutAttributeCenterY relateBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY .......]];

居中对齐。

上述类型的“关系约束”(我个人称之为)是我倾向于用于指定两个视图之间的关系的类型,例如居中对齐,相对定位。

另一方面,根据我自己的观察,视觉格式化语言对于将视图相互固定更有用。

这是一个演示应用:

ViewController.h

@interface ViewController : UIViewController

@property (nonatomic, strong) UIView *outerView;
@property (nonatomic, strong) UIView *innerView;

@property (nonatomic, strong) NSLayoutConstraint *outerViewHeightConstraint;

@end

ViewController.m

- (void)viewDidLoad 
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    [self initViews];
    [self initConstraints];


    // change height of outerView after 3 seconds
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^

        [self changeHeight];

    );


-(void)changeHeight

    self.outerViewHeightConstraint.constant = 150;

    [UIView animateWithDuration:1.0 animations:^
        [self.innerView layoutIfNeeded];
        [self.view layoutIfNeeded];
    ];


-(void)initViews

    self.outerView = [[UIView alloc] init];
    self.outerView.backgroundColor = [UIColor purpleColor];

    self.innerView = [[UIView alloc] init];
    self.innerView.backgroundColor = [UIColor redColor];

    [self.outerView addSubview:self.innerView];

    [self.view addSubview:self.outerView];


-(void)initConstraints

    self.outerView.translatesAutoresizingMaskIntoConstraints = NO;
    self.innerView.translatesAutoresizingMaskIntoConstraints = NO;

    id views = @
                 @"outerView": self.outerView,
                 @"innerView": self.innerView
                 ;

    // outer view constraints
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[outerView(300)]" options:0 metrics:nil views:views]];

    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.outerView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]];

    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.outerView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];

    // give outerView a default height e.g. 300
    // note we can animate the height of outerview later using this var
    self.outerViewHeightConstraint = [NSLayoutConstraint constraintWithItem:self.outerView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeHeight multiplier:1.0 constant:300.0];

    [self.view addConstraint:self.outerViewHeightConstraint];



    // inner view constraints
    [self.outerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-10-[innerView]-10-|" options:0 metrics:nil views:views]];
    [self.outerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[innerView(50)]" options:0 metrics:nil views:views]];

    [self.outerView addConstraint:[NSLayoutConstraint constraintWithItem:self.innerView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.outerView attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]];

    [self.outerView addConstraint:[NSLayoutConstraint constraintWithItem:self.innerView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.outerView attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];

运行应用程序 3 秒后,您会看到外部视图(紫色视图)的高度缩小,而红色内部视图在紫色视图中保持居中并保持其高度。

您也可以旋转视图。

【讨论】:

一个问题self.innerView.NSLayoutAttributeCenterY = self.outerView.NSLayoutAttributeCenterY + 0,现在outerView的center应该是320*480屏幕中的240,如果是这样,innerView在superView self.outerView中的Y也是240? 不太清楚你的意思抱歉,但我会说尝试使用我上面的代码并更改outerView的约束,使outerView的顶部等于self.view的顶部(所以outerView从顶部开始而不是以self.view为中心)。查看 innerView 是否在 outerView 中保持居中。

以上是关于以编程方式使用自动布局约束在视图中垂直对齐中间的子视图的主要内容,如果未能解决你的问题,请参考以下文章

以编程方式将自动布局约束添加到恒定宽度和高度的子视图

ios自动布局视觉格式-对齐

以编程方式添加约束会破坏自动布局约束

将右对齐约束添加到以编程方式添加的子视图

iOS底部对齐具有编程自动布局约束的对象

我们可以将具有自动布局的 XIB 加载为以编程方式创建的没有自动布局的视图的子视图,并使用父视图调整子视图的大小吗?