Интервал UIStackView нарушает ограничения, когда не в set updateConstraints

У меня простой ViewController с пользовательским подпредставлением под названием MyView:

import UIKit

class ViewController: UIViewController {

    let myView = MyView()

    override func viewDidLoad() {
       super.viewDidLoad()
       myView.translatesAutoresizingMaskIntoConstraints = false
       view.addSubview(myView)
       myView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -8.0).isActive = true
       myView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 8.0).isActive = true
       myView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -8.0).isActive = true
   }

}

class MyView: UIView {

    let stackView: UIStackView
    let label = UILabel()
    let label2 = UILabel()

    init() {
      stackView = UIStackView(arrangedSubviews: [label, label2])
      super.init(frame: .zero)

      stackView.axis = .vertical

      label.translatesAutoresizingMaskIntoConstraints = false
      label.text = "Label 1"
      label2.translatesAutoresizingMaskIntoConstraints = false
      label2.text = "Label 2"
      stackView.spacing = 8.0        
      addSubview(stackView)
   }

   required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
   }

   override func updateConstraints() {
        super.updateConstraints()
        stackView.fillSuperview()
   }

}

Когда я запускаю это, я получаю следующие ломающиеся ограничения в консоли:

2018-03-23 16:11:58.960493+0100 ViewWithStackView[75612:10756278] [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:0x608000280f00 'UISV-canvas-connection' UIStackView:0x7f8438e07510.top == UILabel:0x7f8438d06740'Label 1'.top   (active)>",
"<NSLayoutConstraint:0x608000280fa0 'UISV-canvas-connection' V:[UILabel:0x7f8438e07790'Label 2']-(0)-|   (active, names: '|':UIStackView:0x7f8438e07510 )>",
"<NSLayoutConstraint:0x608000280ff0 'UISV-spacing' V:[UILabel:0x7f8438d06740'Label 1']-(8)-[UILabel:0x7f8438e07790'Label 2']   (active)>",
"<NSLayoutConstraint:0x608000280550 'UIView-Encapsulated-Layout-Height' UIStackView:0x7f8438e07510.height == 0   (active)>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x608000280ff0 'UISV-spacing' V:[UILabel:0x7f8438d06740'Label 1']-(8)-[UILabel:0x7f8438e07790'Label 2']   (active)>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
2018-03-23 16:11:58.961737+0100 ViewWithStackView[75612:10756278] 
    [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. 
(Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
     "<NSAutoresizingMaskLayoutConstraint:0x6080002812c0 h=--& v=--& UIStackView:0x7f8438e07510.height == 0   (active)>",
"<NSLayoutConstraint:0x608000280f00 'UISV-canvas-connection' UIStackView:0x7f8438e07510.top == UILabel:0x7f8438d06740'Label 1'.top   (active)>",
"<NSLayoutConstraint:0x608000280fa0 'UISV-canvas-connection' V:[UILabel:0x7f8438e07790'Label 2']-(0)-|   (active, names: '|':UIStackView:0x7f8438e07510 )>",
"<NSLayoutConstraint:0x608000280ff0 'UISV-spacing' V:[UILabel:0x7f8438d06740'Label 1']-(8)-[UILabel:0x7f8438e07790'Label 2']   (active)>"
)     
Will attempt to recover by breaking constraint 

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

Теперь, если я переместить следующую строку stackView.spacing = 8.0 к updateConstraints метод, ограничения не будут нарушены. Таким образом, следующий код работает нормально без предупреждения / ошибки в консоли:

import UIKit

class ViewController: UIViewController {

    let myView = MyView()

    override func viewDidLoad() {
       super.viewDidLoad()
       myView.translatesAutoresizingMaskIntoConstraints = false
       view.addSubview(myView)
       myView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -8.0).isActive = true
       myView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 8.0).isActive = true
       myView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -8.0).isActive = true
   }

}

class MyView: UIView {

    let stackView: UIStackView
    let label = UILabel()
    let label2 = UILabel()

    init() {
      stackView = UIStackView(arrangedSubviews: [label, label2])
      super.init(frame: .zero)

      stackView.axis = .vertical

      label.translatesAutoresizingMaskIntoConstraints = false
      label.text = "Label 1"
      label2.translatesAutoresizingMaskIntoConstraints = false
      label2.text = "Label 2"        
      addSubview(stackView)
   }

   required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
   }

   override func updateConstraints() {
        super.updateConstraints()
        stackView.fillSuperview()
        stackView.spacing = 8.0
   }

}

Почему движется stackView.spacing = 8.0 в updateConstraints решить эту проблему / удалить предупреждения / ошибки?

Спасибо за объяснение:)

2 ответа

Решение

Похоже, это ограничение, которое вы не хотите

"<NSLayoutConstraint:0x608000280550 'UIView-Encapsulated-Layout-Height' UIStackView:0x7f8438e07510.height == 0   (active)>"

Первое, что я попробую, это

stackView.translatesAutoresizingMaskIntoConstraints = false

Кроме того, я не знаю, что stackView.fillSuperview() делает, но вам, вероятно, было бы лучше добавить ограничения к нему, чтобы заполнить представление.

В первом случае stackView имеет нулевую высоту, потому что вы не установили для него рамку (в init до fillSuperview()), поэтому установка интервала 8 между двумя метками вызовет конфликт, но во втором случае кадр равен нулю, а интервал равен нулю, а две метки будут иметь нулевую высоту в соответствии с (внутренним размером содержимого), поэтому в этом случае нет конфликт случится, тогда вы установите интервал в updateConstraints но в этот момент stackView имеет кадр, равный его superView в соответствии с этой строкой fillSuperview() так что все идет гладко и

Другие вопросы по тегам