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

时间:2014-12-27 00:14:54

标签: ios cocoa-touch 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");

}

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

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

3 个答案:

答案 0 :(得分:30)

问题是你正在做一些与#34; uninstalled"无关的事情。故事板中的约束。他们在那里但不在那里。 "卸载"约束仅适用于大小类!如果要在旋转时让自动让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;
}

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

答案 1 :(得分:13)

我遇到了类似的情况。

我在界面构建器中创建了两组NSLayoutConstraints。每套一箱。安装了一套"安装了#34;另一个没有。

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

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

顺便说一下:Strang我使用了#34;已安装/未安装"另一个viewcontroller上的aproach,它的工作原理。

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

答案 2 :(得分:3)

可以使用这个工作流程,尽管很明显这不是Apple目前支持的用例。

诀窍是卸载约束(如@matt也指出的那样),但要在布局发生之前在viewDidLoad()子类的UIViewController中停用它们(而你的冲突约束会导致问题。)

我现在正在使用这种方法,它完美无缺。理想情况下,当然,我们有能力直观地创建约束组,并通过激活和停用它们(如中间有免费动画)将它们用作关键帧:)