如何使用自动布局约束调整嵌入式 UIViewController 的大小和位置?

How to size and position an embedded UIViewController using Auto Layout constraints?

这是我想做的: 我的故事板包含一个 UIViewController,只有几个控件。它的高度不到半个屏幕。为简单起见,我们将其称为 DataViewControllerDataViewController 通过“Container View”嵌入到其他 UIViewControllers 中。

虽然“Container View”显示DataViewController,但它仍然需要明确设置height。否则界面构建器会抱怨不明确的约束。

现在,我如何告诉“Container View”它的大小应该是 DataViewController 所要求的大小? IE。没有在 Interface Builder 中设置硬编码的显式 height(我担心如果字体大小发生变化,这会破坏布局)?

或者换句话说:您如何 size/position 将 UIViewControllers 嵌入到 Interface Builder 中?

如果您希望 childViewContainer 负责其宽度和高度,这里有一种方法:

  • 在您的父视图控制器中设置宽度和高度限制并select在构建时删除。它们就在这里,因此界面构建器不再抱怨缺少约束。

  • (您可以)在情节提要尺寸检查器选项卡中将子视图控制器的模拟尺寸从固定尺寸更改为自由尺寸。

  • 技巧如下:在您的父视图控制器中,viewDidLoad 禁用第一个子视图上的 translatesAutoresizingMaskIntoConstraints,然后自己简单地重新定义 containerView 对其子视图的约束 - 您的子视图控制器的根视图 - 如下所示:

Objective-C

- (void)viewDidLoad {
    [super viewDidLoad];
    self.containerView.subviews[0].translatesAutoresizingMaskIntoConstraints = NO;
}

#pragma mark - Constraints

- (void)updateViewConstraints {
    [super updateViewConstraints];
    [self initConstraints];
}

- (void)initConstraints {
    if (!self.didSetConstraints) {
        self.didSetConstraints = YES;

        self.containerView.subviews[0].translatesAutoresizingMaskIntoConstraints = NO;

        NSDictionary *views = @{@"subview" : self.containerView.subviews[0]};

        [self.containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[subview]|" options:0 metrics:nil views:views]];
        [self.containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[subview]|" options:0 metrics:nil views:views]];
    }
}

Swift

override func viewDidLoad() {
    super.viewDidLoad()
    containerView.subviews[0].translatesAutoresizingMaskIntoConstraints = false
}

// Mark: Constraints

override func updateViewConstraints() {
    super.updateViewConstraints()
    initConstraints()
}

func initConstraints() {
    if !didSetConstraints {
        didSetConstraints = true

        containerView.subviews[0].translatesAutoresizingMaskIntoConstraints = false

        let views = ["subview": containerView.subviews[0]]

        containerView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[subview]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views))
        containerView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[subview]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views))
    }
}

现在您的子视图控制器(链接到容器视图)完全负责其内容大小。因此,您必须设置约束,让根视图计算其大小以满足它所持有的约束。

在您的内容视图控制器中设置 preferredContentSize(在您的示例中 DataViewController),如下所示

override func viewDidLoad() {
    super.viewDidLoad()
    preferredContentSize = CGSize(width: 400, height: 200)
}

当 child 添加到 parentViewController 时,parentViewController 会收到有关首选大小的通知。在 parent

上调用以下函数 func preferredContentSizeDidChange(forChildContentContainer container: UIContentContainer)

在这种方法中,您可以将容器更改为 child 的首选大小。
例如,将高度更改为 child/content

的首选高度
override func preferredContentSizeDidChange(forChildContentContainer container: UIContentContainer) {
    // heightConstraint is a IBOutlet to your NSLayoutConstraint you want to adapt to height of your content
    heigtConstraint.constant = container.preferredContentSize.height
}

如果你嵌入了segue,只需做:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let viewController = segue.destination as? EmbeddedViewController {
      viewController.view.translatesAutoresizingMaskIntoConstraints = false
    }
}