Невозможно удовлетворить ограничения с вложенными представлениями стека - PullRequest
0 голосов
/ 26 февраля 2020

Я медленно схожу с ума, пытаясь отладить предупреждение Unable to satisfy constraints в консоли, которое появляется, когда я перехожу из iPhone Portrait в iPhone Landscape. Я работаю над представлением типа Dashboard с вложенными представлениями стека. Верхний стек меняет ось на .horizontal, если класс размера width является регулярным.

Просмотр иерархии:

  • Просмотр
    • Scrollview
      • Базовое представление
        • Представление стека панели управления
          • Вверх вид в стеке
            • вид в прогрессе
            • вид в виде статистики
          • вид в среднем
          • вид снизу

enter image description here

Код

  • Все компоненты Имеют translatesAutoresizingMaskIntoConstraints = false в viewDidLoad
  • При обнаружении изменения класса размера ограничения обрабатываются
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {

    setupDashboardView()
}

func setupDashboardView() {
    let sizeClass = self.traitCollection

    if sizeClass.isIpad {
        topStack.axis = .horizontal
        topStackHeight.constant = (self.dashboardStack.bounds.height*0.3)
        progressViewWidth.constant = (self.dashboardStack.bounds.width*0.25)
        progressViewHeight.isActive = false
    } else if sizeClass.isIphonePortrait {
        topStack.axis = .vertical
        topStackHeight.constant = self.view.frame.width*1.5
        progressViewWidth.isActive = false
        progressViewHeight.isActive = true
        progressViewHeight.constant = self.view.frame.width
    } else if sizeClass.isIphoneLandscape {
        progressViewHeight.isActive = false
        topStack.axis = .horizontal
        topStackHeight.constant = self.view.frame.height*0.5
        progressViewWidth.isActive = true
        progressViewWidth.constant = self.view.frame.width*0.25
        }
        dashboardStack.spacing = 5
        topStack.spacing = 5

        self.updateViewConstraints()
        self.viewDidLayoutSubviews()
    }


extension UITraitCollection {
    var isIpad: Bool {
        return horizontalSizeClass == .regular && verticalSizeClass == .regular
    }
    var isIphoneLandscape: Bool {
        return verticalSizeClass == .compact
    }
    var isIphonePortrait: Bool {
        return horizontalSizeClass == .compact && verticalSizeClass == .regular
    }
    var isIphone: Bool {
        return isIphoneLandscape || isIphonePortrait
    }
}

//For constraint debugging
extension NSLayoutConstraint {
    override public var description: String {
        let id = identifier ?? ""
        return "id: \(id), constant: \(constant)"
    }
}

Вывод отладчика

Получается при повороте iPhone от портрета до пейзажа.

[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. 
(
    "id: , constant: 0.0",
    "id: , constant: 0.0",
    "id: , constant: 0.0",
    "id: , constant: 0.0",
    "id: progressWidth, constant: 224.0",
    "id: s, constant: 5.0",
    "id: scrollTrail, constant: 5.0",
    "id: UIScrollView-frameLayoutGuide-width, constant: 0.0",
    "id: UISV-canvas-connection, constant: 0.0",
    "id: UISV-canvas-connection, constant: 0.0",
    "id: UISV-canvas-connection, constant: 0.0",
    "id: UIView-Encapsulated-Layout-Width, constant: 896.0",
    "id: UIViewSafeAreaLayoutGuide-left, constant: 44.0",
    "id: UIViewSafeAreaLayoutGuide-right, constant: 44.0"
)

Will attempt to recover by breaking constraint 
id: progressWidth, constant: 224.0

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.
2020-02-26 11:27:51.128311+0000 Haem Data PG Std[9632:2228108] [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. 
(
    "id: progressHeight, constant: 414.0",
    "id: topStackHeight, constant: 185.0",
    "id: UISV-canvas-connection, constant: 0.0",
    "id: UISV-canvas-connection, constant: 0.0"
)

Will attempt to recover by breaking constraint 
id: progressHeight, constant: 414.0

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.

1 Ответ

0 голосов
/ 26 февраля 2020

Ограничения, которые зависят от других действий макета, могут стать хитрыми. Автоматическое размещение делает несколько «проходов», поскольку оно пытается удовлетворить все ограничения.

Это особенно заметно с пропорциональными ограничениями и с ограничениями, на которые могут влиять представления стека (которые выполняют свои собственные действия макета).

Чтобы избежать предупреждений, вам часто нужно настроить приоритеты ограничений.

И вам нужно быть осторожным с порядком при активации / деактивации ограничений.

I выложите объекты, как вы показали, и для вашего случая вы должны быть в состоянии исправить положение:

  • измените Приоритет progressViewHeight, progressViewWidth и topStackHeight ограничение каждого к 999.
  • порядок изменений ограничений должен быть
    • установка .isActive = false для представлений / меток / et c должна go первая
    • изменение .constant значений на видах / метках / et c должно go далее
    • с последующей настройкой .isActive = true на видах / метках / et c
    • с последующим изменением .constant значения в представлениях стека
    • и, наконец, изменение .axis стековых представлений

Не все это жесткие правила, но по опыту это хороший путь к go.

Попробуйте изменить Приоритеты для ваших ограничений, как указано выше, и измените setupDashboardView() fun c следующим образом:

func setupDashboardView() {
    let sizeClass = self.traitCollection

    if sizeClass.isIpad {
        progressViewHeight.isActive = false
        progressViewWidth.constant = (self.dashboardStack.bounds.width*0.25)
        topStackHeight.constant = (self.dashboardStack.bounds.height*0.3)
        topStack.axis = .horizontal
    } else if sizeClass.isIphonePortrait {
        progressViewWidth.isActive = false
        progressViewHeight.isActive = true
        progressViewHeight.constant = self.view.frame.width
        topStackHeight.constant = self.view.frame.width*1.5
        topStack.axis = .vertical
    } else if sizeClass.isIphoneLandscape {
        progressViewHeight.isActive = false
        progressViewWidth.constant = self.view.frame.width*0.25
        progressViewWidth.isActive = true
        topStackHeight.constant = self.view.frame.height*0.5
        topStack.axis = .horizontal
    }
    dashboardStack.spacing = 5
    topStack.spacing = 5

    // not needed
    //self.updateViewConstraints()

    // NEVER call this yourself
    //self.viewDidLayoutSubviews()
}
...