如何以编程方式更改或更新 NSLayoutConstraint

Posted

技术标签:

【中文标题】如何以编程方式更改或更新 NSLayoutConstraint【英文标题】:How to change or update NSLayoutConstraint programmatically 【发布时间】:2015-06-03 12:24:09 【问题描述】:

我已经使用代码以编程方式实现了 AutoLayout:

- (void)addConstraintWithListNavigationViewController:(UIView *)listViewNavigation y:(CGFloat)y height:(CGFloat)height

    //WIDTH_ListTableView = 0.4

    //set x = 0;
    NSLayoutConstraint *constraintToAnimate1 = [NSLayoutConstraint constraintWithItem:listViewNavigation
                                                                            attribute:NSLayoutAttributeLeft
                                                                            relatedBy:NSLayoutRelationEqual
                                                                               toItem:self.view
                                                                            attribute:NSLayoutAttributeLeft
                                                                           multiplier:0.00
                                                                             constant:0];
    [self.view addConstraint:constraintToAnimate1];


    //set y = y;
    NSLayoutConstraint *constraintToAnimate2 = [NSLayoutConstraint constraintWithItem:listViewNavigation
                                                                            attribute:NSLayoutAttributeTop
                                                                            relatedBy:NSLayoutRelationEqual
                                                                               toItem:self.view
                                                                            attribute:NSLayoutAttributeBottom
                                                                           multiplier:0.00
                                                                             constant:y];
    [self.view addConstraint:constraintToAnimate2];








    //set Width = self.view.frame.size.width*0.4
    NSLayoutConstraint *constraintToAnimate3 = [NSLayoutConstraint constraintWithItem:listViewNavigation
                                                                            attribute:NSLayoutAttributeWidth
                                                                            relatedBy:NSLayoutRelationEqual
                                                                               toItem:self.view
                                                                            attribute:NSLayoutAttributeWidth
                                                                           multiplier:1-WIDTH_ListTableView
                                                                             constant:0.0];
    [self.view addConstraint:constraintToAnimate3];





    //Set height = height
    NSLayoutConstraint *constraintToAnimate4 = [NSLayoutConstraint constraintWithItem:listViewNavigation
                                                                            attribute:NSLayoutAttributeHeight
                                                                            relatedBy:NSLayoutRelationEqual
                                                                               toItem:nil
                                                                            attribute:NSLayoutAttributeNotAnAttribute
                                                                           multiplier:0.00
                                                                             constant:height];
    [self.view addConstraint:constraintToAnimate4];

这很完美,但是每次这个 ViewController 收到 Notification 时,它都会运行:

[self.view layoutIfNeeded];

但我想根据连接的布尔变量设置 listViewNavigation 的宽度。

if(connected)
        listViewNavigation.view.frame.size.width = 0.4 * self.view.frame.size.width;
    
    else
        listViewNavigation.view.frame.size.width = 0.6 * self.view.frame.size.width;
    

但我不知道如何更新 NSLayoutConstraint :

NSLayoutConstraint *constraintToAnimate3 = [NSLayoutConstraint constraintWithItem:PreView
                                                                            attribute:NSLayoutAttributeWidth
                                                                            relatedBy:NSLayoutRelationEqual
                                                                               toItem:self.view
                                                                            attribute:NSLayoutAttributeWidth
                                                                           multiplier:1 - WIDTH_ListTableView
                                                                             constant:0.0];
[self.view addConstraint:constraintToAnimate3];

当这个 ViewController 收到通知时。

【问题讨论】:

【参考方案1】:

我认为你有两个选择。

选项 1 保留一个属性

@property (strong,nonatomic)NSLayoutConstraint *constraintToAnimate3;

然后使用这个属性来

self.constraintToAnimate3 = [NSLayoutConstraint constraintWithItem:PreView
                                                                        attribute:NSLayoutAttributeWidth
                                                                        relatedBy:NSLayoutRelationEqual
                                                                           toItem:self.view
                                                                        attribute:NSLayoutAttributeWidth
                                                                       multiplier:1
                                                                         constant:-1 * 0.4 * self.view.frame.size.width];
[self.view addConstraint:self.constraintToAnimate3];

当你想改变时

if(connected)
    self.constraintToAnimate3.constant = -1 *0.6 * self.view.frame.size.width;

else
    self.constraintToAnimate3.constant = -1 *0.4 * self.view.frame.size.width;

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

选项 2 设置constraintToAnimate3的标识符

constraintToAnimate3.identifier = @"1234"

然后搜索得到约束

NSLayoutConstraint * constraint3 = nil;
NSArray * constraints = self.view.constraints;
for (NSLayoutConstraint * constraint in constraints) 
    if ([constraint.identifier isEqualToString:@"1234"]) 
        constraint3 = constraint;
        break;
    

然后如Option1所示改变常数

更新: 如果在我发布的代码中使用常量

PreView.frame.size.with = self.view.size.width * multiplier + constant

【讨论】:

这种方式需要更新常量,所以我把约束改成“multiplier:1,constant:0.4 * self.view.frame.size.width”,可以设置常量为你喜欢的正确常数 listViewNavigation.frame.size.width 变得太大。如果我设置乘数 = 0,那么就可以了。但我记得苹果不允许设置乘数 = 0; 所以,我认为如果我们设置“multiplier = 1.0”,我们应该设置“constant = - 0.4*self.view.frame.size.width” 是的,我没有从您发布的代码中获得有关您的视图确切大小的详细信息。这只是宽度的关系。你可以决定它是什么。 PreView.width = self.view.width * 乘数 + 常数。我想你可以弄清楚【参考方案2】:

好的,我知道了。

[self.view removeConstraint:self.constraintOld];
[self.view addConstraint:self.constraintNew];

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

【讨论】:

这是最好的方法,即使您正在编辑完全相同的约束。【参考方案3】:

重要的是,您不仅要在视图中添加约束,还要记住它们。

如果您只需要更改其常量,则更改约束是最简单的 - 常量是约束中唯一可以在以后重复更改的部分。为此,您需要自行存储约束。

否则,您需要删除旧约束并添加新约束。由于您通常有多个约束,因此存储具有可能需要替换的约束集的数组,然后更新整个数组。您还可以使用 activateConstraints 和 deactivateConstraints 方法。

【讨论】:

以上是关于如何以编程方式更改或更新 NSLayoutConstraint的主要内容,如果未能解决你的问题,请参考以下文章

如何更新以编程方式更改的元素的 v-model?

如何以编程方式确定 iPhone 的密码是不是已更改或删除?

如何摆脱或更改情节提要以编程方式创建 segue

以编程方式更新/更改 s-s-rS 数据源(未共享)

如何以编程方式更改 Azure 云服务或 VM 的 IP 地址?

如何以编程方式更新 UITextView maximumNumberOfLines 并查看 UI 更新。