簡體   English   中英

自動布局問題

[英]Autolayout issue

我正在開發一個使用自動布局的應用程序。 我正在執行以下步驟:

  1. 步驟1:在viewDidLoad創建一個按鈕

     [super viewDidLoad]; self.view.translatesAutoresizingMaskIntoConstraints = NO; _button1 = [UIButton buttonWithType:UIButtonTypeRoundedRect]; _button1.translatesAutoresizingMaskIntoConstraints = NO; [_button1 setTitle:@"B" forState:UIControlStateNormal]; [self.view addSubview:_button1]; 
  2. 步驟2:在updateViewConstraints方法中實現約束

     [super updateViewConstraints]; [self.view removeConstraints:self.view.constraints]; if (UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation)) { NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:_button1 attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0f constant:100.0f]; [self.view addConstraint:constraint]; NSLayoutConstraint *constraint1 = [NSLayoutConstraint constraintWithItem:_button1 attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeRight multiplier:1.0f constant:-100.0f]; [self.view addConstraint:constraint1]; NSLayoutConstraint *constraint2 = [NSLayoutConstraint constraintWithItem:_button1 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0f constant:200.0f]; [self.view addConstraint:constraint2]; NSLayoutConstraint *constraint3 = [NSLayoutConstraint constraintWithItem:_button1 attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0f constant:-100.0f]; [self.view addConstraint:constraint3]; _button1.backgroundColor = [UIColor redColor]; } else{ NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:_button1 attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0f constant:200.0f]; [self.view addConstraint:constraint]; NSLayoutConstraint *constraint1 = [NSLayoutConstraint constraintWithItem:_button1 attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeRight multiplier:1.0f constant:-200]; [self.view addConstraint:constraint1]; NSLayoutConstraint *constraint2 = [NSLayoutConstraint constraintWithItem:_button1 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0f constant:50.0f]; [self.view addConstraint:constraint2]; NSLayoutConstraint *constraint3 = [NSLayoutConstraint constraintWithItem:_button1 attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0f constant:-50.0f]; [self.view addConstraint:constraint3]; _button1.backgroundColor = [UIColor blueColor]; } 

但是當我切換設備方向時,控制台將打印以下內容:

無法同時滿足約束條件。 以下列表中至少有一個約束是您不想要的約束。 嘗試以下操作:(1)查看每個約束,並嘗試找出不期望的約束; (2)查找添加了一個或多個不必要約束的代碼並進行修復。 (注意:如果看到的是您不了解的NSAutoresizingMaskLayoutConstraints,請參閱有關UIView屬性的文檔translationsAutoresizingMaskIntoConstraints)(“ UIView:0x8a461c0(Names:'|':UIWindow:0x8a42970)>”,“” ,“ UIButton:0x8a45ea0(名稱:'|':UIView:0x8a461c0)>”,“”)

將嘗試通過打破約束來恢復

中斷objc_exception_throw以在調試器中捕獲此錯誤。 列出的UIView的UIConstraintBasedLayoutDebugging類別中的方法也可能會有所幫助。

誰能告訴我這種布局有什么問題嗎?

問題是您在按鈕仍然有約束的情況下在updateViewConstraints調用[super updateViewConstraints] 因此,當您從橫向過渡到縱向時,您仍然具有橫向按鈕約束(縱向無法滿足),但是要求主視圖更新其(人像)約束。 如果在刪除所有現有按鈕約束之后將調用移至[super updateViewConstraints]任何位置,則狀態應該良好。


幾個方面:

  1. 如果使用情節提要/ NIBS,則應刪除顯示以下內容的行:

     self.view.translatesAutoresizingMaskIntoConstraints = NO; 

    但請保留以下內容:

     _button1.translatesAutoresizingMaskIntoConstraints = NO; 
  2. 我會小心翼翼地取消所有限制。 我通常會保留要刪除的約束數組,這樣一來,我可以輕松地刪除僅需要刪除並將要重構的約束。 在您的情況下,刪除所有內容可能沒問題,但是隨着在視圖中添加越來越多的約束,跟蹤要刪除和重建的對象可能更容易:

     @property (nonatomic, strong) NSArray *verticalConstraints; @property (nonatomic, strong) NSArray *horizontalConstraints; 
  3. 我可能建議使用VFL,這會更簡潔一些:

     - (void)updateViewConstraints { if (self.horizontalConstraints) [self.view removeConstraints:self.horizontalConstraints]; if (self.verticalConstraints) [self.view removeConstraints:self.verticalConstraints]; [super updateViewConstraints]; NSDictionary *views = NSDictionaryOfVariableBindings(_button1); NSDictionary *metrics = nil; if (UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation)) { metrics = @{@"left" : @100, @"right" : @100, @"top" : @200, @"bottom" : @100}; _button1.backgroundColor = [UIColor redColor]; } else{ metrics = @{@"left" : @200, @"right" : @200, @"top" : @50, @"bottom" : @50}; _button1.backgroundColor = [UIColor blueColor]; } self.horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(left)-[_button1]-(right)-|" options:0 metrics:metrics views:views]; self.verticalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(top)-[_button1]-(bottom)-|" options:0 metrics:metrics views:views]; [self.view addConstraints:self.horizontalConstraints]; [self.view addConstraints:self.verticalConstraints]; } 

也可以通過使用約束的乘數和常量值來創建單個約束(針對每個方向)同時適用於縱向和橫向的約束而無需檢查約束的方向(如果在情節提要中創建視圖,則需要以在添加這些約束之前刪除您在其中所做的任何約束-您可以通過選中要刪除的每個約束的屬性檢查器中的“占位符-生成時刪除”框來自動完成該約束)。 在您的特定情況下,我認為這些值有效:

- (void)viewDidLoad {
    [super viewDidLoad];

    _button1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    _button1.translatesAutoresizingMaskIntoConstraints = NO;
    [_button1 setTitle:@"B" forState:UIControlStateNormal];
    [self.view addSubview:_button1];
    NSLayoutConstraint *topCon = [NSLayoutConstraint constraintWithItem:_button1 attribute:NSLayoutAttributeTop relatedBy:0 toItem:self.view attribute:NSLayoutAttributeBottom multiplier:.9375 constant:-250];
    NSLayoutConstraint *bottomCon = [NSLayoutConstraint constraintWithItem:_button1 attribute:NSLayoutAttributeBottom relatedBy:0 toItem:self.view attribute:NSLayoutAttributeBottom multiplier:.6875 constant:50];
    NSLayoutConstraint *leftCon = [NSLayoutConstraint constraintWithItem:_button1 attribute:NSLayoutAttributeLeft  relatedBy:0 toItem:self.view attribute:NSLayoutAttributeRight multiplier:.625 constant:-100];
    NSLayoutConstraint *rightCon = [NSLayoutConstraint constraintWithItem:_button1 attribute:NSLayoutAttributeRight relatedBy:0 toItem:self.view attribute:NSLayoutAttributeRight multiplier:.375 constant:100];
    [self.view addConstraints:@[topCon,bottomCon,rightCon,leftCon]];
}

請注意,self.view的屬性在頂部約束的底部,而在左側約束的右邊。 使用乘數時,必須這樣做,因為left和top屬性值為零,所以乘以任何東西都將是無用的。

手工計算這些值很麻煩,因此我實際上並沒有那樣設置。 相反,我在NSLayoutConstraint上寫了一個類別,使我可以像這樣設置約束(可以在http://jmp.sh/v/fgHhRNX2twlrgG338CDz上找到具有該類別的exampleProject):

[self.view addConstraint:[NSLayoutConstraint rightConstraintForView:_button1 viewAttribute:NSLayoutAttributeRight superview:self.view portraitValue:100 landscapeValue:200]];
[self.view addConstraint:[NSLayoutConstraint topConstraintForView:_button1 viewAttribute:NSLayoutAttributeTop superview:self.view portraitValue:200 landscapeValue:50]];
[self.view addConstraint:[NSLayoutConstraint bottomConstraintForView:_button1 viewAttribute:NSLayoutAttributeBottom superview:self.view portraitValue:100 landscapeValue:50]];
[self.view addConstraint:[NSLayoutConstraint leftConstraintForView:_button1 viewAttribute:NSLayoutAttributeLeft superview:self.view portraitValue:100 landscapeValue:200]];

通常,布局約束是在IB中構建的,然后根據方向更改進行調整 ,而不是像您想做的那樣丟棄並重新創建方向更改約束。

無論如何,問題似乎在於您沒有刪除所有必需的約束。 該行[self.view removeConstraints:self.view.constraints]; 只刪除約束自己的看法約束和忽略了一個事實,有可能就與其他視圖(即上海華)約束view

我不確定這是否是您的問題,但是我會嘗試調整現有的約束條件,看看是否可以解決問題。 如果可以幫助您,可以使IBOutlet用於布局約束。

我將您的內容復制並粘貼到一個全新的項目中,並且效果很好。 因此,您的項目中可能還有其他可能會干擾的內容。 您正在使用情節提要嗎?

#import "DemoViewController.h"

@interface DemoViewController()

@property (nonatomic, strong) UIButton *button1;

@end

@implementation DemoViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.view.translatesAutoresizingMaskIntoConstraints = NO;

    _button1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    _button1.translatesAutoresizingMaskIntoConstraints = NO;
    [_button1 setTitle:@"B" forState:UIControlStateNormal];
    [self.view addSubview:_button1];
}

- (void)updateViewConstraints
{
    [super updateViewConstraints];

    [self.view removeConstraints:self.view.constraints];

    if (UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation))
    {
        NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:_button1 attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0f constant:100.0f];
        [self.view addConstraint:constraint];

        NSLayoutConstraint *constraint1 = [NSLayoutConstraint constraintWithItem:_button1 attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeRight multiplier:1.0f constant:-100.0f];
        [self.view addConstraint:constraint1];

        NSLayoutConstraint *constraint2 = [NSLayoutConstraint constraintWithItem:_button1 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0f constant:200.0f];
        [self.view addConstraint:constraint2];

        NSLayoutConstraint *constraint3 = [NSLayoutConstraint constraintWithItem:_button1 attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0f constant:-100.0f];
        [self.view addConstraint:constraint3];


        _button1.backgroundColor = [UIColor redColor];
    } else{
        NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:_button1 attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0f constant:200.0f];
        [self.view addConstraint:constraint];

        NSLayoutConstraint *constraint1 = [NSLayoutConstraint constraintWithItem:_button1 attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeRight multiplier:1.0f constant:-200];
        [self.view addConstraint:constraint1];

        NSLayoutConstraint *constraint2 = [NSLayoutConstraint constraintWithItem:_button1 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0f constant:50.0f];
        [self.view addConstraint:constraint2];

        NSLayoutConstraint *constraint3 = [NSLayoutConstraint constraintWithItem:_button1 attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0f constant:-50.0f];
        [self.view addConstraint:constraint3];

        _button1.backgroundColor = [UIColor blueColor];
    }
}

@end

和AppDelegate:

#import "AppDelegate.h"
#import "DemoViewController.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.window.backgroundColor = [UIColor whiteColor];
    self.window.rootViewController = [[DemoViewController alloc] init];
    [self.window makeKeyAndVisible];
    return YES;
}

@end

如果您刪除此行

self.view.translatesAutoresizingMaskIntoConstraints = NO;

然后,我相信您不應再遇到這個問題,我已經看過幾次了,如果您使用情節提要,那么添加此行代碼將導致使用應用程序時出現這些類型的問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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