[英]Can't change Constraint IBOutlet that is defined for different size classes in IB
我為這個案子做了一個特殊的測試應用程序。 (對不起,已經刪除了)
我在Storyboard
添加了一個關於我的控制器視圖的視圖,在Interface Builder
設置了AutoLayout約束,並使其中一個(垂直空間)不同於不同的大小類。 IB的截圖
因此,對於Any height, Any width
值為0,對於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
}
雖然它在我刪除Interface Builder
Regular height, Regular width
值時有效。
我想念大小班嗎?
問題是,在-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
,因此您必須確保在初始加載時僅進行一次調整。
如果為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];
我遇到了同樣的問題,但它似乎與viewDidLoad vs viewDidLayoutSubviews沒有任何關系。 Interface Builder可以管理不同大小類的備用約束常量,但是當您嘗試在代碼中更新NSLayoutConstraint.constant時,該常量不與任何特定大小類(包括活動大小類)相關聯。
從Apple文檔, 更改大小類的約束常量 (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和setter,反映了已經通過IB提供的功能。
我檢查它正在工作的示例項目中的相同場景可能是您忘記連接NSLayoutConstraint topVerticalConstraint
與storyboard。
在viewDidLayoutSubviews中更改約束的常量
- (void) viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
if (IS_IPHONE4) {
self.topConstraint.constant = 10;
self.bottomButtonTop.constant = 10;
self.pageControlTopConstraint.constant = 5;
}
}
最簡單的解決方案
if (self.view.traitCollection.verticalSizeClass == UIUserInterfaceSizeClassRegular && self.view.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact) {
// for iPhone
cnicTopConstraint.constant = -60;
} else {
// for iPad
cnicTopConstraint.constant = -120;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.