2012-10-10 122 views
82

我知道很多人已經問過很多關於這個問題的問題,但即使有了答案,我也無法使其工作。以編程方式創建佈局約束條件

當我在故事板上處理約束時,很容易,但在代碼中我很難。 例如,我嘗試將視圖保留在右側並根據屏幕方向確定屏幕的高度。這是我的代碼:

UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 748)]; 
myView.backgroundColor = [UIColor redColor]; 
[self.view addSubview:myView]; 
[self.view addConstraints:[NSLayoutConstraint 
    constraintsWithVisualFormat:@"V:|-[myView(>=748)]-|" 
    options:0 metrics:nil 
    views:NSDictionaryOfVariableBindings(myView)]]; 

它並不滿足一定的制約。我不明白什麼是錯的。另外,爲什麼我不能使用像self.myView這樣的屬性而不是像myView這樣的局部變量?

+0

在上面的代碼中,vivi是什麼? – iDev

+13

請將標題改爲「iOS」而不是「IOS」 - 後者是指Cisco的交換機/路由器操作系統。使我困惑。謝謝。 – armani

+1

關於這方面的幾個問題:(1)當它「不滿足某些約束條件」時,你會得到什麼錯誤? (2)你是否正在將自動調整大小轉換爲'myView'上的約束? (3)什麼是'vivi'(如ACB問)? (4)你有'myView'屬性在'self'聲明嗎? – Tim

回答

105

上的蘋果文檔在代碼中使用自動佈局時,設置該框架什麼也不做。因此,您在上述視圖中指定寬度爲200的事實,在對其設置約束時並不意味着什麼。爲了使視圖的約束集明確,需要四件事情:任何給定狀態的x位置,y位置,寬度和高度。

目前在上面的代碼中,只有兩個(相對於超視圖的高度,相對於超視圖的位置)。除此之外,根據視圖的超視圖約束如何設置,您有兩個必需的約束可能會發生衝突。 如果超級觀點有一個必要的約束,指定它的高度是一些小於748的值,你會得到一個「不可滿足的約束」例外。

事實上,在設置約束之前設置視圖的寬度意味着什麼。它甚至不考慮舊框架,並基於它爲這些視圖指定的所有約束來計算新框架。在處理代碼中的自動佈局時,我通常只使用initWithFrame:CGRectZero或簡單地init來創建新視圖。

要爲你創造你的問題口頭描述的佈局要求的約束集,你需要一些水平的限制添加到綁定的寬度和X位置,以便給完全指定佈局:

[self.view addConstraints:[NSLayoutConstraint 
    constraintsWithVisualFormat:@"V:|-[myView(>=748)]-|" 
    options:NSLayoutFormatDirectionLeadingToTrailing 
    metrics:nil 
    views:NSDictionaryOfVariableBindings(myView)]]; 

[self.view addConstraints:[NSLayoutConstraint 
    constraintsWithVisualFormat:@"H:[myView(==200)]-|" 
    options:NSLayoutFormatDirectionLeadingToTrailing 
    metrics:nil 
    views:NSDictionaryOfVariableBindings(myView)]]; 

口頭描述此佈局如下開始與垂直約束:

MyView的將填充它的父的高度與頂部和底部填充 等於標準空間。 myView的超級視圖的最小高度爲,爲748pts。 myView的寬度是200pts,右邊的填充等於 反對其超視圖的標準空間。

如果你只想視圖填滿整個上海華的身高沒有限制的上海華的身高,那麼你就只需要省略在視覺格式文本(>=748)參數。如果您認爲(>=748)參數是必須的,給它一個高度 - 你不必在這種情況下:釘扎視圖使用巴(|)的上海華盈的邊緣或與空間(|--|)語法吧,你給您可以查看y位置(將視圖固定在單邊上)以及帶有高度的y位置(固定兩邊的視圖),從而滿足您爲視圖設置的約束。

在關於你的第二個問題:

使用NSDictionaryOfVariableBindings(self.myView)(如果你有對MyView的一個屬性設置),餵養到您的VFL在你VFL文本中使用self.myView,你可能會得到一個異常時,自動佈局嘗試解析您的VFL文本。它與字典鍵中的點符號以及試圖使用valueForKeyPath:的系統有關。 See here for a similar question and answer

+0

不要忘記像UILabel這樣的對象具有固有的大小,您不必設置該對象的寬度或高度,只需設置其位置即可。但是,如果您設置高度或寬度,我相信它會消除兩者,然後您必須提供兩者。 –

+0

即使這個答案沒有回答我的問題,但它幫助我意識到了一些事情。謝謝你! :) –

+1

到目前爲止在互聯網上唯一簡潔和可讀的自動佈局介紹。 –

5

關於您關於屬性的第二個問題,僅當您將其聲明爲類中的某個屬性時,纔可以使用self.myView。由於myView是一個局部變量,因此不能以這種方式使用它。有關這方面的更多詳細信息,我建議您通過Declared Properties

60

嗨我一直在使用這個頁面很多約束和「如何」。它花了我永遠的時間去實現我需要的點:

myView.translatesAutoresizingMaskIntoConstraints = NO; 

得到這個例子的工作。謝謝Userxxx,Rob M.,特別是larsacus在這裏的解釋和代碼,它非常寶貴。

這裏是全代碼即可獲得上面的例子來運行:

UIView *myView = [[UIView alloc] init]; 
myView.backgroundColor = [UIColor redColor]; 
myView.translatesAutoresizingMaskIntoConstraints = NO; //This part hung me up 
[self.view addSubview:myView]; 
//needed to make smaller for iPhone 4 dev here, so >=200 instead of 748 
[self.view addConstraints:[NSLayoutConstraint 
          constraintsWithVisualFormat:@"V:|-[myView(>=200)]-|" 
          options:NSLayoutFormatDirectionLeadingToTrailing 
          metrics:nil 
          views:NSDictionaryOfVariableBindings(myView)]]; 

[self.view addConstraints:[NSLayoutConstraint 
          constraintsWithVisualFormat:@"H:[myView(==200)]-|" 
          options:NSLayoutFormatDirectionLeadingToTrailing 
          metrics:nil 
          views:NSDictionaryOfVariableBindings(myView)]]; 
5

爲什麼我不能使用像self.myView,而不是像MyView的局部變量的屬性?

嘗試使用:

NSDictionaryOfVariableBindings(_view) 

代替self.view

+0

這使我的應用程序崩潰,它給消息: '無法解析約束格式: polylineImageView不是視圖字典中的關鍵字。' –

4

也請注意,從iOS9我們可以定義約束編程「更簡潔,更易於閱讀」使用子類的新輔助類的NSLayoutAnchor

從文檔的一個例子:

[self.cancelButton.leadingAnchor constraintEqualToAnchor:self.saveButton.trailingAnchor constant: 8.0].active = true; 
+2

感謝'.active = true' –

9

斯威夫特版本

更新了斯威夫特3

這個例子將顯示兩種方法以編程方式添加下列約束一樣,如果做它在界面生成器中:

寬度和高度

enter image description here

中心集裝箱

enter image description here

樣板代碼

override func viewDidLoad() { 
    super.viewDidLoad() 

    // set up the view 
    let myView = UIView() 
    myView.backgroundColor = UIColor.blue 
    myView.translatesAutoresizingMaskIntoConstraints = false 
    view.addSubview(myView) 

    // Add constraints code here (choose one of the methods below) 
    // ... 
} 

方法1:錨式

// width and height 
myView.widthAnchor.constraint(equalToConstant: 200).isActive = true 
myView.heightAnchor.constraint(equalToConstant: 100).isActive = true 

// center in container 
myView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true 
myView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true 

方法2:NSLayoutConstraint樣式

// width and height 
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 200).isActive = true 
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 100).isActive = true 

// center in container 
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.centerX, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerX, multiplier: 1, constant: 0).isActive = true 
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.centerY, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerY, multiplier: 1, constant: 0).isActive = true 

  • 錨式結束NSLayoutConstraint文體的優選方法,但是它只能從iOS的9,因此,如果要支持iOS 8的那麼你應該仍然使用NSLayoutConstraint風格。
  • 另請參閱Programmatically Creating Constraints文檔。
  • 有關添加固定約束的類似示例,請參閱this answer
相關問題