我有两个视图控制器,父母和孩子。
所以在viewDidLoad
方法中,我执行以下操作:
ChildViewController* childViewController = [[ChildViewController alloc] init];
[self addChildViewController:childViewController];
// ChildViewController sets his own constraints in viewDidLoad
[self.view addSubview:childViewController.view];
[childViewController didMoveToParentViewController:self];
//
// setup constraints to expand childViewController.view to
// fill the size of parent view controller
//
所以基本上发生的事情是在应用父控制器约束之前在ChildViewController上调用updateViewConstraints
,实际上self.view.frame == CGRectZero
与我在{loadView
方法中指定的完全相同1}}。
ChildViewController
都设置为translatesAutoresizingMaskIntoConstraints
。
在这种情况下设置约束的正确方法是什么,以便NO
更新父母之后的约束?
来自两个控制器的当前日志非常令人沮丧,我不明白如何在viewWillLayoutSubviews之前调用updateViewConstraints:
ChildViewController
答案 0 :(得分:5)
我有类似的情况,我将子控制器添加到可见控制器(弹出窗口)。
我在界面构建器中定义子视图控制器。它的viewDidLoad方法只调用setTranslatesAutoresizingMaskIntoConstraints:NO
然后我在子控制器上定义了这个方法,它接受一个UIViewController参数,即父项。 此方法将自身添加到给定的父视图控制器并定义其自己的约束:
- (void) addPopupToController:(UIViewController *)parent {
UIView *view = [self view];
[self willMoveToParentViewController:parent];
[parent addChildViewController:self];
[parent.view addSubview:view];
[self didMoveToParentViewController:parent];
NSArray *horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[view]-0-|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(view)];
[parent.view addConstraints:horizontalConstraints];
NSArray *verticalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[view]-0-|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(view)];
[parent.view addConstraints:verticalConstraints];
}
然后在父UIViewController(已经显示的那个)内部,当我想显示它调用的子弹出视图控制器时:
PopUpNotificationViewController *popup = [[self storyboard] instantiateViewControllerWithIdentifier:@"NotificationPopup"];
[popup addPopupToController:self];
将子控制器的视图添加到父控制器的视图时,可以定义所需的约束。
答案 1 :(得分:2)
我认为layoutIfNeeded
方法只有在您之前调用setNeedsLayout
时才有效。如果您使用setNeedsLayout
,系统将知道在适当的时间更新。尝试在代码中更改它。
向视图添加约束时,该视图应再次自动布局其子视图以考虑新约束。除非您添加了约束后发生了某些变化,否则不应该调用setNeedsLayout
。您是否将约束添加到视图中,如果是这样:您是否将它们添加到右视图中?
您可以尝试的一件事是继承UIView
,以便在ChildViewController.view
或ParentViewController.view
执行全新布局时看到日志消息:
-(void) layoutSubviews {
[super layoutSubviews];
NSLog(@"layoutSubviews was called on the following view: %@", [view description]);
}
也许这会揭示出你的观点是(或不是)布局他们的子视图的时候。
答案 2 :(得分:2)
您可以在调用addSubview后立即添加约束:不要忘记将translatesAutoresizingMaskIntoConstraints
设置为false
以下是使用约束添加和隐藏子视图控制器的代码片段(受apple guide启发)
<强> 显示 强>
private func display(contentController content : UIViewController)
{
self.addChildViewController(content)
content.view.translatesAutoresizingMaskIntoConstraints = false
self.containerView.addSubview(content.view)
content.didMove(toParentViewController: self)
containerView.addConstraints([
NSLayoutConstraint(item: content.view, attribute: .top, relatedBy: .equal, toItem: containerView, attribute: .top, multiplier: 1, constant: 0),
NSLayoutConstraint(item: content.view, attribute: .bottom, relatedBy: .equal, toItem: containerView, attribute: .bottom, multiplier: 1, constant: 0),
NSLayoutConstraint(item: content.view, attribute: .leading, relatedBy: .equal, toItem: containerView, attribute: .leading, multiplier: 1, constant: 0),
NSLayoutConstraint(item: content.view, attribute: .trailing, relatedBy: .equal, toItem: containerView, attribute: .trailing, multiplier: 1, constant: 0)
])
}
<强> 隐藏 强>
private func hide(contentController content : UIViewController)
{
content.willMove(toParentViewController: nil)
content.view.removeFromSuperview()
content.removeFromParentViewController()
}
答案 3 :(得分:1)
根据the following link,我将约束创建移动到viewWillLayoutSubviews
,这是正确设置视图边界的地方。我觉得这个答案没有解释为什么Child视图控制器的updateViewConstraints在父视图控制器之前调用,或者它可能只是我代码中的一些错误,但是这个解决方法解决了这个问题......
答案 4 :(得分:0)
将用于添加和删除子控制器的代码放入扩展很方便。用法示例:
override func viewDidLoad() {
super.viewDidLoad()
let childController = YourCustomController()
add(childController)
}
代码本身:
extension UIViewController {
func add(_ controller: UIViewController) {
addChild(controller)
view.addSubview(controller.view)
controller.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
controller.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
controller.view.topAnchor.constraint(equalTo: view.topAnchor),
controller.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
controller.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
controller.didMove(toParent: self)
}
func remove() {
guard parent != nil else {
return
}
willMove(toParent: nil)
view.removeFromSuperview()
removeFromParent()
}
}