我为这个案子制作了一个特殊的测试应用程序。 (对不起,它已被删除)
我在Storyboard
的控制器视图中添加了一个视图,在Interface Builder
中设置了AutoLayout约束,并且其中一个(垂直空间)对于不同的大小类是不同的。 Screenshot from IB
因此Any height, Any width
的值为100,Regular height, Regular width
的值为0。
它的效果很好,iPhone上的垂直距离是100,在iPad上它是0。
此外,我为此约束设置了IBOutlet
,并希望在运行时将其更改为10
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *topVerticalConstraint;
似乎我无法改变它,因为它没有效果
- (void)viewDidLoad
{
[super viewDidLoad];
self.topVerticalConstraint.constant = 10; // it doesn't work
}
虽然我在Regular height, Regular width
中移除Interface Builder
的值时会有效。
我是否想念尺寸类?
答案 0 :(得分:13)
问题是,在-viewWillLayoutSubviews
和-viewDidLayoutSubviews
之间发生布局事件之前,约束尚未完全定义,其中IB的所有参数都会发挥作用。
我的经验法则是:
第二个陈述仅考虑对IB中的约束进行代码调整。您在-viewDidLoad中进行的调整将被布局期间在IB中设置的参数覆盖。如果使用代码添加约束,可以在-viewDidLoad中设置它们,因为没有任何内容可以覆盖它们。
我已经改变了你的代码并且它有效:
#import "ViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *topVerticalConstraint;
@property (weak, nonatomic) IBOutlet UIView *square;
@property (assign, nonatomic) BOOL firstLayout;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.firstLayout = YES;
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
if (self.firstLayout) {
self.topVerticalConstraint.constant = 10;
self.firstLayout = NO;
}
}
@end
请注意,在ViewController的生命周期内多次调用-viewDidLayoutSubviews
,因此您必须确保在初始加载时只进行一次调整。
答案 1 :(得分:4)
如果您为IB中的不同大小类设置了不同的值,请执行以下约束:
然后您无法在代码中更改常量值:
self.adHeightConstraint.constant = 0; // value set to 0
[self.view layoutIfNeeded]; // value get back to IB value (44 or 36)
在这种情况下,您可能会看到您的常量值仅在视图重新计算之前一直存在。因此,在[self.view layoutIfNeeded]
之后,常量重置的值回到IB中设置的任何值。
现在,当您需要应用新常量时,简单禁用第一个约束:
self.adHeightConstraint.active = NO;
[self.view layoutIfNeeded];
答案 2 :(得分:1)
我遇到了同样的问题,但它似乎与viewDidLoad vs viewDidLayoutSubviews没有任何关系。 Interface Builder可以管理不同大小类的备用约束常量,但是当您尝试在代码中更新NSLayoutConstraint.constant时,该常量不与任何特定大小类(包括活动大小类)相关联。
来自Apple文档,Changing Constraint Constants for a Size Class(XCode 7,Interface Builder)
我的解决方案是从IB中删除备用常量,并在代码中管理基于大小的约束常量开关,仅针对在代码中更新/修改的特定约束。任何仅通过storyboard / IB管理的约束都可以正常使用备用大小常量。
// XCode 7.0.1, Swift 2.0
static var isCompactHeight : Bool = false;
static var heightOffset : CGFloat {
return (isCompactHeight ? compactHeightOffset : regularHeightOffset);
}
/* applyTheme can be called as early as viewDidLoad */
func applyTheme() {
// This part could go wherever you handle orientation changes
let appDelegate = UIApplication.sharedApplication().delegate;
let window = appDelegate?.window;
let verticalSizeClass = window??.traitCollection.verticalSizeClass ?? UIUserInterfaceSizeClass.Unspecified;
isCompactHeight = (verticalSizeClass == UIUserInterfaceSizeClass.Compact);
// Use heightOffset
changingConstraint.constant = heightOffset;
}
我希望稍后版本的Swift / XCode会引入getter& amp;将基于大小的备选项考虑在内的setter,反映了已经通过IB提供的功能。
答案 3 :(得分:0)
我在示例项目中查看相同的场景,它可能会忘记将NSLayoutConstraint topVerticalConstraint
与故事板连接。
答案 4 :(得分:0)
在viewDidLayoutSubviews中更改约束的常量
- (void) viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
if (IS_IPHONE4) {
self.topConstraint.constant = 10;
self.bottomButtonTop.constant = 10;
self.pageControlTopConstraint.constant = 5;
}
}
答案 5 :(得分:0)
最简单的解决方案:
if (self.view.traitCollection.verticalSizeClass == UIUserInterfaceSizeClassRegular && self.view.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact) {
// for iPhone
cnicTopConstraint.constant = -60;
} else {
// for iPad
cnicTopConstraint.constant = -120;
}