2014-09-21 81 views
5

我試圖創建一個包含2個自定義視圖(B)在其添加一個子類的UIView到筆尖與它的自動佈局約束

視圖B一個UIView(A)使用自動佈局約束,建立和Interface Builder中取得包括約束條件。的UIImageView(前導= 10,尾隨= 10,AlignVertically) - - 的UITextField(前導= 10,尾隨= 10,AlignVertically)

的ViewController A(A是在的viewController

B的筆尖 加入300x300,Align Horizo​​ntal,AlignVertically)

在ViewController中,我將A固定爲300x300和 B1和B2將其前導,尾隨,頂部和底部固定爲0.(這應該使B1和B2爲300x150,原諒我,如果我錯過了什麼)

當加載查看BI使用下面的代碼加載它的筆尖:

override func awakeAfterUsingCoder(aDecoder: NSCoder!) -> AnyObject! { 
    if self.subviews.count == 0 { 
     let bundle = NSBundle(forClass: self.dynamicType) 
     var view = bundle.loadNibNamed("B", owner: nil, options: nil)[0] as B 
     view.setTranslatesAutoresizingMaskIntoConstraints(false) 
     let constraints = self.constraints() 
     self.removeConstraints(constraints) 
     view.addConstraints(constraints) 
     return view 
    } 
    return self 
} 

但是當我嘗試運行此,我得到以下警告,包括崩潰:

The view hierarchy is not prepared for the constraint: <NSLayoutConstraint:0x7f897ad1acc0 V:[TestProject.B:0x7f897af73840(300)]> 
When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView _viewHierarchyUnpreparedForConstraint:] to debug. 

我也嘗試添加該視圖爲視圖B的性質和使用下面的代碼,將其添加到B

NSBundle.mainBundle().loadNibNamed("B", owner: self, options: nil) 
self.addSubview(self.viewOfB); 

這樣做的結果是被添加到的viewController視圖,但它不是採用自己的Nib中的任何AutoLayoutConstraints。

現在我不知道如何將此視圖添加到包含約束的viewController視圖中。我究竟做錯了什麼?有一個更好的方法嗎?

PS:視圖A過去也是自定義的。

PPS:我正在使用Swift來做到這一點,但我確信Objective-C中的解決方案也適用。

+0

看看這個教程同樣大小應該是有幫助的,以使用編程方式創建約束在快速 http://makeapppie.com/2014/07/26/the-swift-swift-tutorial-how-to-use-uiviews-with-auto-layout-programmatically/ – Signo 2014-09-26 13:15:40

回答

4

問題是:constraints檢索self是指self

相反,您必須制定新的約束條件,指的是view以及其他相同的屬性。像這樣:

NSMutableArray *constraints = [NSMutableArray array]; 
for(NSLayoutConstraint *constraint in self.constraints) { 
    id firstItem = constraint.firstItem; 
    id secondItem = constraint.secondItem; 
    if(firstItem == self) firstItem = view; 
    if(secondItem == self) secondItem = view; 
    [constraints addObject:[NSLayoutConstraint constraintWithItem:firstItem 
                 attribute:constraint.firstAttribute 
                 relatedBy:constraint.relation 
                  toItem:secondItem 
                 attribute:constraint.secondAttribute 
                 multiplier:constraint.multiplier 
                 constant:constraint.constant]]; 
} 

/* if you also have to move subviews into `view`. 
for(UIView *subview in self.subviews) { 
    [view addSubview:subview]; 
} 
*/ 

[view addConstraints:constraints]; 

而且,我認爲你應該從self複製一些更多的屬性。

view.frame = self.frame; 
view.autoresizingMask = self.autoresizingMask; 
view.translatesAutoresizingMaskIntoConstraints = self.translatesAutoresizingMaskIntoConstraints; 

對不起的OBJ-C代碼,我從this answer複製:)

+0

輝煌。從來沒有想過如何正確地從自我正確地複製這些約束。 – zmonteca 2015-03-04 01:16:25

5

所有你所得到的錯誤,首先是因爲

  • 你不能調換或之間移動的約束你的視圖
  • 在添加新約束之前必須已將視圖添加到層​​次結構中
  • 約束通常會添加到擁有視圖(或共同祖先)的父視圖。

    (詳細內容見AutoLayout Guide

我建議有鑑於A(CustomView:UIView的)從筆尖文件加載內容(B查看),並加入他們,因爲它的子視圖。

Main View with CustomView A

的技巧是,你需要給你佈置一個內容視圖內B瀏覽,以便您的榫文件中只有一個是根對象。

這樣,當您將內容視圖添加爲視圖子視圖時,所有約束都將轉移(類似於UITableViewCells使用其contentView的方式)。

ContentView xib

重要提示:內容視圖應該是類類型CustomView的。如果您想拖動插座和操作,只需聲明類CustomView的文件的所有者對象並將它們鏈接到那裏。

您的最終視圖層次應該是這樣的:

MainView (ViewController's view) 
    View A 
    Content View 
     B1 View 
     B2 View 

這樣視圖一個有它的佈局在ViewController中的情節提要/ XIB配置和你B的意見將使用約束從相關內容筆尖文件視圖。

所以,唯一的事情就是讓我們要確保的是,內容畫面總會有觀點A.

class CustomView: UIView 
{ 
@IBOutlet var _b1Label: UILabel! 
@IBOutlet var _b2Button: UIButton! 

func loadContentView() 
{ 
    let contentNib = UINib(nibName: "CustomView", bundle: nil) 

    if let contentView = contentNib.instantiateWithOwner(self, options: nil).first as? UIView 
    { 
     self.addSubview(contentView) 

     // We could use autoresizing or manually setting some constraints here for the content view 
     contentView.translatesAutoresizingMaskIntoConstraints = true 
     contentView.autoresizingMask = [.FlexibleHeight, .FlexibleWidth] 
     contentView.frame = self.bounds 
    } 
} 

override init(frame: CGRect) 
{ 
    super.init(frame: frame) 

    loadContentView() 
} 

required init(coder aDecoder: NSCoder) 
{ 
    super.init(coder: aDecoder); 

    loadContentView() 
} 

} 
+0

我嘗試了多種方式爲嵌入式視圖手動添加約束,但沒有像這種方法一樣可靠地工作 - 翻譯桅杆並打開translatesAutoresizingMaskIntoConstraints .. – 2015-09-22 03:58:29