Используйте Autolayout для контроллеров дочернего представления

У меня снова проблемы с автораскладкой...

Вот что я хочу получить в итоге:

дизайн

Я делаю все в коде с контроллером родительского представления и контроллером дочернего представления сверху, по центру и снизу.

В конце концов, я хочу иметь возможность установить высоту контроллера вида сверху на его внутреннюю высоту - вот где я сейчас терплю неудачу... Контроллер вида сверху имеет вертикальное представление стека, используемое для размещения элементов (для иметь возможность добавлять и удалять представления по мере необходимости в конце).

Эта реализация...

import UIKit

class ParentViewController: UIViewController {

    lazy var topChildView: UIView = {
        let topView = topChildViewController.view!
        topView.backgroundColor = .red
        topView.translatesAutoresizingMaskIntoConstraints = false
        topView.accessibilityIdentifier = "top"
        return topView
    }()

    lazy var topChildViewController: TopChildViewController = {
        let topVC = TopChildViewController()
        return topVC
    }()

    lazy var centerChildView: UIView = {
        let centerView = centerChildViewController.view!
        centerView.backgroundColor = .blue
        centerView.translatesAutoresizingMaskIntoConstraints = false
        centerView.accessibilityIdentifier = "center"
        return centerView
    }()

    lazy var centerChildViewController: CenterChildViewController = {
        let centerVC = CenterChildViewController()
        return centerVC
    }()

    lazy var bottomChildView: UIView = {
        let bottomView = bottomChildViewController.view!
        bottomView.backgroundColor = .green
        bottomView.translatesAutoresizingMaskIntoConstraints = false
        bottomView.accessibilityIdentifier = "bottom"
        return bottomView
    }()

    lazy var bottomChildViewController: BottomChildViewController = {
        let bottom = BottomChildViewController()
        return bottom
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .gray

        self.addChild(topChildViewController)
        self.view.addSubview(topChildView)

        self.addChild(centerChildViewController)
        self.view.addSubview(centerChildView)

        self.addChild(bottomChildViewController)
        self.view.addSubview(bottomChildView)

        NSLayoutConstraint.activate([
            topChildView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 12),
            topChildView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 12),
            topChildView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -12),
            topChildView.heightAnchor.constraint(equalToConstant: topChildView.intrinsicContentSize.height),

            centerChildView.topAnchor.constraint(equalTo: topChildView.bottomAnchor),
            centerChildView.leadingAnchor.constraint(equalTo: topChildView.leadingAnchor),
            centerChildView.trailingAnchor.constraint(equalTo: topChildView.trailingAnchor),

            bottomChildView.leadingAnchor.constraint(equalTo: topChildView.leadingAnchor),
            bottomChildView.trailingAnchor.constraint(equalTo: topChildView.trailingAnchor),
            bottomChildView.heightAnchor.constraint(equalToConstant: 100),
            bottomChildView.topAnchor.constraint(equalTo: centerChildView.bottomAnchor),
            bottomChildView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -12),
        ])
    }

}

class TopChildViewController: UIViewController {

    lazy var stackView: UIStackView = {
        let s = UIStackView()
        s.translatesAutoresizingMaskIntoConstraints = false
        s.axis = .vertical
        s.distribution = .fillEqually
        s.spacing = 6
        return s
    }()

    lazy var textField: UITextField = {
        let t = UITextField()
        t.borderStyle = .roundedRect
        t.placeholder = "Some fancy text"
        t.accessibilityIdentifier = "textfield"
        t.translatesAutoresizingMaskIntoConstraints = false
        return t
    }()

    lazy var label: UILabel = {
        let l = UILabel()
        l.accessibilityIdentifier = "label"
        l.translatesAutoresizingMaskIntoConstraints = false
        l.text = "Awesome Label"
        l.textAlignment = .center
        return l
    }()

    override func loadView() {
        view = UIView()

        view.addSubview(stackView)

        stackView.addArrangedSubview(textField)
        stackView.addArrangedSubview(label)

        NSLayoutConstraint.activate([


            textField.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 12),
            textField.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 12),
            textField.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -12),

            label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            label.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -12)
        ])
    }
}

class CenterChildViewController: UIViewController {
    override func loadView() {
        view = UIView()
    }
}

class BottomChildViewController: UIViewController {
    override func loadView() {
        view = UIView()
    }
}

... приводит к такому результату:

результат

Хотя я знаю об ошибке (похоже, что встроенная высота недоступна в то время, когда я пытаюсь получить к ней доступ, см. ниже), я не знаю, как ее решить — что я упускаю?

Нужно ли создавать ограничение где-то еще? Мне бы очень хотелось иметь возможность контролировать его с родительского контроллера представления...

[LayoutConstraints] Unable to simultaneously satisfy constraints.
  Probably at least one of the constraints in the following list is one
you don't want.   Try this:       (1) look at each constraint and try to
figure out which you don't expect;        (2) find the code that added the
unwanted constraint or constraints and fix it.  (
    "<NSLayoutConstraint:0x600002306d50 top.height == - 1   (active, names: top:0x7f81c1e1f120 )>" )

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x600002306d50 top.height == - 1   (active, names:
top:0x7f81c1e1f120 )>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints
to catch this in the debugger. The methods in the
UIConstraintBasedLayoutDebugging category on UIView listed in
<UIKitCore/UIView.h> may also be helpful.


person ASSeeger    schedule 29.03.2020    source источник
comment
Вау, это раздражает: после того, как кто-то другой принял изменение формата некоторых моих постов, довольно невпечатляюще теперь мои встроенные скриншоты отсутствуют, и я не могу понять, как их снова добавить — извините за это!   -  person ASSeeger    schedule 29.03.2020
comment
Спасибо за редактирование/решение проблемы с картинками, @Yonat   -  person ASSeeger    schedule 29.03.2020


Ответы (1)


Немного поигравшись, я понимаю, что мне нужно полностью опустить topChildView.heightAnchor.constraint(equalToConstant: topChildView.intrinsicContentSize.height), , чтобы заставить его работать...

Итак, ограничения, которые я предоставляю в ParentViewController.viewDidLoad(), следующие:

NSLayoutConstraint.activate([
            topChildView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 12),
            topChildView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 12),
            topChildView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -12),

            centerChildView.topAnchor.constraint(equalTo: topChildView.bottomAnchor),
            centerChildView.leadingAnchor.constraint(equalTo: topChildView.leadingAnchor),
            centerChildView.trailingAnchor.constraint(equalTo: topChildView.trailingAnchor),

            bottomChildView.leadingAnchor.constraint(equalTo: topChildView.leadingAnchor),
            bottomChildView.trailingAnchor.constraint(equalTo: topChildView.trailingAnchor),
            bottomChildView.heightAnchor.constraint(equalToConstant: 100),
            bottomChildView.topAnchor.constraint(equalTo: centerChildView.bottomAnchor),
            bottomChildView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -12),
        ])
person ASSeeger    schedule 29.03.2020