activateConstraints:和deactivateConstraints:在IB中创建的约束旋转后不持久

rde*_*mar 27 cocoa-touch ios autolayout nslayoutconstraint

新的NSLayoutConstraint方法activateConstraints:deactivateConstraints:不会出现与IB-创建的约束正常工作(他们正常工作的代码创建的约束).我用一个按钮创建了一个简单的测试应用程序,该按钮有两组约束.安装的一组具有centerX和centerY约束,而另一组(已卸载)具有顶部和左侧约束(常数10).按钮方法切换这些约束集.这是代码,

@interface ViewController ()
@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *uninstalledConstraints;
@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *installedConstraints;
@end

@implementation ViewController


- (IBAction)switchconstraints:(UIButton *)sender {
    [NSLayoutConstraint deactivateConstraints:self.installedConstraints];
    [NSLayoutConstraint activateConstraints:self.uninstalledConstraints];
}


-(void)viewWillLayoutSubviews {
    NSLog(@"installed: %@    uninstalled: %@", ((NSLayoutConstraint *)self.installedConstraints[0]).active ? @"Active" : @"Inactive", ((NSLayoutConstraint *)self.uninstalledConstraints[0]).active ? @"Active" : @"Inactive");

}
Run Code Online (Sandbox Code Playgroud)

当应用程序启动时,按钮处于由其安装的约束定义的正确的居中位置.在按钮的操作方法中执行激活/取消激活后,按钮会正确移动到新位置,但是当我将视图旋转到横向时,它会移回到最初定义的位置(尽管日志仍然显示新激活的设置为活跃).当我旋转回肖像时,按钮保持在其初始位置(在屏幕中央),现在日志显示初始约束集合处于活动状态,而我激活的约束处于非活动状态.

问题是,这是一个错误,还是这些方法不应该以这种方式使用IB定义的约束?

mat*_*att 30

问题是你在故事板中做了与"未安装"约束不一致的事情.他们在那里但不在那里."未安装"约束仅适用于大小类!如果要在旋转时自动让Xcode交换约束,可以使用它们.Xcode无法应对你正在做的事情.但是如果你在代码中创建第二组约束,一切都会正常工作.

所以,这样做.删除两个"已卸载"约束,并删除uninstalledConstraints插座.现在用以下代码替换整个视图控制器代码:

@property (strong, nonatomic) NSMutableArray *c1;
@property (strong, nonatomic) NSMutableArray *c2;
@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *installedConstraints;
@property (weak,nonatomic) IBOutlet UIButton *button;
@end

@implementation ViewController {
    BOOL did;
}

- (void)viewDidLayoutSubviews {
    NSLog(@"did");
    if (!did) {
        did = YES;
        self.c1 = [self.installedConstraints mutableCopy];
        self.c2 = [NSMutableArray new];
        [self.c2 addObject:
         [NSLayoutConstraint constraintWithItem:self.button attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTopMargin multiplier:1 constant:30]];
        [self.c2 addObject:
         [NSLayoutConstraint constraintWithItem:self.button attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeadingMargin multiplier:1 constant:30]];
    }
}

- (IBAction)switchconstraints:(UIButton *)sender {
    [NSLayoutConstraint deactivateConstraints:self.c1];
    [NSLayoutConstraint activateConstraints:self.c2];
    NSMutableArray* temp = self.c1;
    self.c1 = self.c2;
    self.c2 = temp;
}
Run Code Online (Sandbox Code Playgroud)

现在反复按下按钮.如你所见,它在两个位置之间跳跃.现在旋转应用程序; 按钮保持原样.

  • 我已经看到了使用大小类安装和卸载约束的文档,但我似乎错过了对于"安装"或"卸载"约束意味着什么的基本解释.所以,我(错误)的理解是,一个卸载的约束是IB相当于在代码中创建约束,而不是将其添加到视图中.你能指出我这个概念有详细记载的地方吗? (3认同)
  • 有关于编写自适应应用程序的WWDC视频,它讨论了"已安装"复选框的用途. - 我再说一遍,你希望在Interface Builder中设计两组约束并不合理.相反,您有一个简单而有说服力的用例.您应该将其作为增强请求提交给Apple.但就目前而言,你偶然发现了一个边缘情况,应该避免它(正如你自己的结果所示). (3认同)

小智 13

我遇到了类似的情况.

我在界面构建器中创建了两组NSLayoutConstraints.每套一箱.一套是"安装"另一套没有.

当我切换案例时,相应的布局约束集被激活而另一个被去除了.正如Qusteion中所描述的那样,前后旋转不能正常工作.

通过在界面构建器中安装两个集来解决这个问题.为了摆脱警告我第二组使用了较低优先级(999).这对我有用.

顺便说一句:Strang我在另一个viewcontroller上使用了"已安装/未安装"的方法,它们的工作原理.

在不工作的情况下,viewcontroller嵌入在containerview中,也许这就是原因.