簡體   English   中英

無法更改為IB中的不同大小類定義的約束IBOutlet

[英]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的所有參數都起作用。 我的經驗法則是:

  • 如果您使用框架手動定位視圖,您可以盡早-viewDidLoad,
  • 如果您使用自動布局約束進行定位,請盡早進行調整-viewDidLayoutSubviews;

第二個陳述僅考慮對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中設置的任何值。

解決方案:

  1. 添加具有所需值的相同屬性的第二個約束 (在我的情況下,它是高度)。 您可以在IB中設置此值或在代碼中更改它。
  2. 為此新約束設置低優先級。 由於它的優先級較低,因此不會發生任何沖突。
  3. 現在,當您需要應用新常量時,只需禁用第一個約束

     self.adHeightConstraint.active = NO; [self.view layoutIfNeeded]; 

我遇到了同樣的問題,但它似乎與viewDidLoad vs viewDidLayoutSubviews沒有任何關系。 Interface Builder可以管理不同大小類的備用約束常量,但是當您嘗試在代碼中更新NSLayoutConstraint.constant時,該常量不與任何特定大小類(包括活動大小類)相關聯。

從Apple文檔, 更改大小類的約束常量 (XCode 7,Interface Builder) 多個大小類的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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM