如何在显示旋转上以编程方式更改布局约束

时间:2014-12-14 20:37:27

标签: ios constraints programmatically-created

对于应用程序(兼容iOS 7),我需要在横向和纵向模式下具有完全不同的布局。我看到了以编程方式设置约束并在轮换时更改它们的唯一方法。所以我使用IB设置我的界面,然后以编程方式设置约束。

我在某处看到了首先删除所有约束的方法,然后创建并添加新约束,然后在父视图上设置约束的更新标志。我希望元素只是屏幕的整个宽度,而另一个是另一个:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {

    self.landscapeConstraints = [NSMutableArray new];
    self.portraitConstraints = self.view.constraints;

    //creation of the viewsDictionary

    [self.landscapeConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[segmentedControl]-|" options:0 metrics:nil views:viewsDictionary]];
    [self.landscapeConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[fullText]-|" options:0 metrics:nil views:viewsDictionary]];
    [self.landscapeConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[bubbleTitle]-|" options:0 metrics:nil views:viewsDictionary]];
    [self.landscapeConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[bubble]-|" options:0 metrics:nil views:viewsDictionary]];
    [self.landscapeConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[chartView]-|" options:0 metrics:nil views:viewsDictionary]];
    [self.landscapeConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(20)-[segmentedControl]-[fullText]-[bubbleTitle]-[bubble]-[chartView]|" options:0 metrics:nil views:viewsDictionary]];

    [self.view removeConstraints:self.portraitConstraints];
    [self.view addConstraints:self.landscapeConstraints];

    [self.view setNeedsUpdateConstraints];
}

我的问题:这种方式是完整和正确的吗?

我提出这个问题,因为旋转后元素太大了。轮换后看起来超级视图的大小不正确。因此,所有元素都太大了,似乎最大元素(长文本标签)给出的宽度比屏幕大很多。如果我在约束中设置了一个大小的元素(例如[segmentedControl(== 500)],那么这个元素的大小就可以了,所有其他元素也都有这个大小。

命令

NSLog(@"%@", [self.view performSelector:@selector(_autolayoutTrace)]);

给了我所有元素的类似内容:

*UIView:0x7f9a38f36510- AMBIGUOUS LAYOUT for UIView:0x7f9a38f36510.minX{id: 9}, UIView:0x7f9a38f36510.minY{id: 12}, UIView:0x7f9a38f36510.Width{id: 15}, UIView:0x7f9a38f36510.Height{id: 17}

任何人都可以暗示我在哪里做错了吗?我现在正在努力工作几个小时......

修改

我真正不理解的是:在我删除所有约束之后的解决方案似乎是通过这样的约束来定义超视图的大小:

NSDictionary *viewsDictionary = @{ @"view":self.view};

[self.landscapeConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[view(360)]" options:0 metrics:nil views:viewsDictionary]];
[self.landscapeConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[view(650)]" options:0 metrics:nil views:viewsDictionary]];

否则所有视图都会崩溃,因为superview似乎没有大小。即使有这些额外的约束,视图也离得太远(大约20px)!

任何人都可以向我解释一下吗?我是否真的需要使用当前的窗口大小手动生成该约束?我希望包含视图(这是主窗口)具有全屏大小。

1 个答案:

答案 0 :(得分:0)

您可以像设置一样设置布局约束,但也可以使用IBOutlet引用它们,只需以编程方式更改它们(并在之后调用layoutIfNeeded)。在没有看到布局的情况下分析代码非常困难,但是您的日志显示约束不够精确(模糊)。要知道哪个视图是哪个视图,您也可以单独记录视图,并为每个视图获取缺少的约束。然后逐个设置约束,使其不再模糊。

在您的声明中:

@property (nonatomic, weak) IBOutlet NSLayoutConstraint *leftMarginViewXYZ;

然后在Interface Builder中右键单击约束并绘制对ViewController的引用。释放按钮时,选择正确的约束。

然后,您可以在代码中使用

更改约束
self.leftMarginViewXYZ.constant = 123;
[self.view layoutIfNeeded];