2015-02-24 43 views
2

我有一個非常簡單的Custom Container View Controller,在兩個視圖之間交換。當添加內容視圖(帶有.xib的UIViewController,其中包含一個帶AutoLayout約束的按鈕)時,它可以很好地排除並且沒有衝突的約束。按下按鈕可將該視圖交換爲另一個視圖(同一視圖類型的另一個實例),該視圖也可以很好地排除並且不存在衝突約束。添加視圖,刪除它並再次添加它打破自動佈局約束

當我再次交換視圖以重新插入第一個視圖(已存儲並且與之前刪除的視圖相同)時,iOS「無法同時滿足約束」。每次在第二次交換之後iOS都會拋出不滿足約束條件的相同警告。

代碼,用於顯示一個視圖控制器:

func displayController(controller:UIViewController) { 

    self.addChildViewController(controller) 
    controller.view.setTranslatesAutoresizingMaskIntoConstraints(false) 
    controller.view.frame = CGRectMake(0.0, 0.0, self.view.bounds.width, self.view.bounds.height) 
    self.view.addSubview(controller.view) 

    self.view.addConstraint(NSLayoutConstraint(item: controller.view, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Top, multiplier: 1.0, constant: 0)) 
    self.view.addConstraint(NSLayoutConstraint(item: controller.view, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Leading, multiplier: 1.0, constant: 0)) 
    self.view.addConstraint(NSLayoutConstraint(item: controller.view, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Width, multiplier: 1.0, constant: 0)) 
    self.view.addConstraint(NSLayoutConstraint(item: controller.view, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Height, multiplier: 1.0, constant: 0)) 

    controller.didMoveToParentViewController(self) 
    self.currentViewController = controller; 
} 

代碼用於除去視圖控制器

func hideController(controller:UIViewController) { 

    controller.willMoveToParentViewController(nil) 
    controller.view.removeFromSuperview() 
    controller.removeFromParentViewController() 

    if self.currentViewController == controller { 

     self.currentViewController = nil 
    } 
} 

和代碼爲交換意見只是調用二者的那些方法:

func switchToViewController(controller:UIViewController) { 

    if self.currentViewController != nil { 

     self.hideController(self.currentViewController!) 
    } 

    self.displayController(controller) 
} 

這兩個子視圖控制器都使用與在InterfaceBuilder中設置約束的大按鈕相同的.xib。

第一次添加和刪除這些子視圖時,它們顯示正常,沒有警告。

First child view controller Second child view controller

一旦第一種觀點再次添加按鈕的高度是錯誤的,我得到一個「無法同時滿足約束」的警告。

First child view controller added a second time

2015-02-23 21:40:17.223 Swift Container View Controller[27976:832141] Unable to simultaneously satisfy constraints. 
(
"<NSLayoutConstraint:0x7fa57a41eed0 'UIView-Encapsulated-Layout-Height' V:[UIView:0x7fa57a715b40(667)]>", 
"<NSLayoutConstraint:0x7fa57a71d1c0 V:[UIButton:0x7fa57a71bce0'Switch to Yellow View']-(413)-| (Names: '|':UIView:0x7fa57a71cff0)>", 
"<NSLayoutConstraint:0x7fa57a71d260 V:|-(262)-[UIButton:0x7fa57a71bce0'Switch to Yellow View'] (Names: '|':UIView:0x7fa57a71cff0)>", 
"<NSLayoutConstraint:0x7fa57a71d300 V:[UIButton:0x7fa57a71bce0'Switch to Yellow View'(125)]>", 
"<NSLayoutConstraint:0x7fa57a48ff10 UIView:0x7fa57a71cff0.height == UIView:0x7fa57a715b40.height>" 
) 

我相當肯定,按鈕上的限制是正確的,因爲他們制定出正確的第一次,但隨後在後續使用中破裂。

+1

我打賭你的xib高800點? iPhone 6是667點高。錯誤是說它不能使800 = 667,但爲什麼它不會失敗,最初我不能說。 – 2015-02-24 04:50:43

回答

2

問題是你有不止一種方式定義的子視圖控制器的高度。這三行是重要

"<NSLayoutConstraint:0x7fa57a71d1c0 V:[UIButton:0x7fa57a71bce0'Switch to Yellow View']-(413)-| (Names: '|':UIView:0x7fa57a71cff0)>", 

這告訴我們按鈕的底部413

"<NSLayoutConstraint:0x7fa57a71d260 V:|-(262)-[UIButton:0x7fa57a71bce0'Switch to Yellow View'] (Names: '|':UIView:0x7fa57a71cff0)>", 

這告訴我們的頂部被約束到視圖的底部具有恆定(距離)該按鈕被限制在視圖的頂部,其常數(距離)爲262。

"<NSLayoutConstraint:0x7fa57a71d300 V:[UIButton:0x7fa57a71bce0'Switch to Yellow View'(125)]>", 

這告訴我們按鈕被限制爲具有恆定的(距離)的125

一個固定的高度爲了同時滿足這3個約束條件。視圖控制器視圖必須具有800(413 + 262 + 125)的高度,不多也不少。

當您添加控制器查看到容器的視圖,您試圖再次與新的約束

self.view.addConstraint(NSLayoutConstraint(item: controller.view, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Height, multiplier: 1.0, constant: 0)) 

這裏所展示的日誌定義高度:

"<NSLayoutConstraint:0x7fa57a41eed0 'UIView-Encapsulated-Layout-Height' V:[UIView:0x7fa57a715b40(667)]>" 

由於視圖的高度不能同時爲667pts和800pts,必須打破一些約束條件,並且界面顯示不正確。

要解決這個問題,我們需要重新考慮按鈕周圍的約束條件。答案是不使用按鈕的頂部和底部約束。而是定義按鈕的寬度和高度,然後將按鈕中心x和y與視圖控制器中心x和y匹配。請記住,如果您有從邊到邊(即從上到下或導致尾隨)鏈接的需求(優先級1000)約束,這將定義超級視圖的大小。最好只限制兩邊和寬度和高度,或者與父母的相對點(例如中心)相匹配。

+0

謝謝@ P-double的剪輯幀高度。一旦我解決了約束條件,就不再需要優先級設置。 – skabob11 2015-02-25 00:27:40

+0

沒問題。 Autolayout有時候會讓人頭疼:) – 2015-02-25 09:42:15

0

問題是'UIView-Encapsulated-Layout-Height'約束。這是一個由SDK添加的約束,原因不明。它很少發生,但是當它發生了,我發現的唯一的解決方法是給我自己的制約因素之一的999優先級在您的情況:

let heightConstraint = NSLayoutConstraint(item: controller.view, attribute: .Height, relatedBy: .Equal, toItem: self.view, attribute: .Height, multiplier: 1.0, constant: 0) 
heightConstraint.priority = 999 
self.view.addConstraint(heightConstraint) 

的SDK約束添加只能暫時使您的佈局應按預期工作。

+0

謝謝@lassej。那樣做了。 – skabob11 2015-02-24 05:46:10

+0

這可能會修復它,但它不是正確的答案 – 2015-02-24 16:28:43

+0

這隻能實現丟棄高度限制之一。子視圖控制器視圖將仍然具有800 – 2015-02-24 16:45:07

相關問題