使用自动布局约束将子类UIView添加到Nib

我正在尝试创build一个包含2个自定义视图(B)的UIView(A)

视图B使用Autolay Const Constraints进行设置,并在Interface Builder中进行设置,包括约束。 A被添加到viewController的Nib中

B – UIImageView(Leading = 10,Trailing = 10,AlignVertically) – UITextField(Leading = 10,Trailing = 10,AlignVertically)

ViewController A(300×300,水平alignment,垂直alignment)

在ViewController中,我将A固定为300×300,B1和B2将其前导,尾随,顶部和底部固定为0.(这应该使B1和B2成为300×150,如果我错过了某些东西,请原谅我)

当加载View BI时,使用下面的代码来加载它的Nib:

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中的解决scheme也可以工作。

首先你得到的错误是因为

  • 您不能在视图之间交换或移动约束
  • 在添加新约束之前,视图必须已经添加到层次结构中
  • 约束通常添加在保存视图(或共同祖先)的父视图中。

    (更多细节参见AutoLayout Guide )

我会build议查看A(CustomView:UIView)从nib文件加载内容(B视图),并添加它们的子视图。

主视图与自定义视图A

诀窍是您需要在内容视图中布局B 视图,以便您的nib文件只有一个根对象。

这样,当你添加内容视图作为视图的一个子视图,所有的约束将转移(类似于UITableViewCells如何使用他们的contentView)。

ContentView xib

重要说明 :内容视图应该是类typesCustomView。 如果您想拖动网点和操作,只需声明类CustomView的文件的所有者对象,并将其链接到那里。

您的最终视图层次结构应如下所示:

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

这种方式视图A有在ViewController的storyboard / xib中configuration的布局,而B视图将使用与内容视图相关的nib文件中的约束。

所以唯一要做的就是确保内容视图的视图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() } } 

问题是: self检索的constraints是指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代码,我从这个答案复制:)