Як я можу змінити пріоритет обмежень під час виконання


86

У мене є подання, яке має динамічну висоту, і я намагаюся змінити цей пріоритет висоти подання під час виконання.

Ось моя частина коду;

if (index == 0) {

    surveyViewHeightConstraint.constant = 0;
    surveyViewHeightConstraint.priority = 1000;

} else if (index == 1) {

    surveyViewHeightConstraint.constant = 163;
    surveyViewHeightConstraint.priority = 500;

}

Я змінюю індекс за допомогою кнопки. Коли я запускаю цей код, я отримую таку помилку:

*** Assertion failure in -[NSLayoutConstraint setPriority:], /SourceCache/Foundation/Foundation-1141.1/Layout.subproj/NSLayoutConstraint.m:174

У чому моя помилка тут?

Відповіді:


172

Як зазначено в NSLayoutConstraintдовідковому класі :

Пріоритети не можуть змінюватися з необов’язкових на необхідні або з обов’язкових на необмежені. Виняток буде створено, якщо пріоритет NSLayoutPriorityRequiredв OS X або UILayoutPriorityRequirediOS зміниться на нижчий пріоритет або якщо нижчий пріоритет зміниться на необхідний пріоритет після додавання обмежень у подання. Перехід від одного необов’язкового пріоритету до іншого необов’язкового пріоритету дозволяється навіть після встановлення обмеження у поданні.

Використовуйте пріоритет 999 замість 1000. Технічно це не буде абсолютно необхідним, але це буде вищий пріоритет, ніж будь-що інше.


4
Дякуємо за вашу приємну відповідь, але якщо я використовую 999 замість 1000, я не можу приховати свій погляд, призначивши 0 обмеженню висоти.
Le'Kirdok,

Це ще одна проблема. У вас можуть бути інші суперечливі обмеження. Якщо ваш код більше не виходить з ладу, але анімація перегляду все ще неправильна, позначте це питання як вирішене; потім відкрийте ще одну.
Cyrille 02

приємно, це не проблема використовувати різні значення (999, 900, 500 тощо) :)
user924

7
Серйозно? Чи є щось, що працює нормально у розробці iOS? Стільки речей доводилося робити вручну та / або доводити тонни обхідного коду до причин системних помилок або непідтримуваності. Вибачте за неконструктивний коментар.
Лютень

6
Здається, це обмеження було знято в iOS 13. Я спробував змінити обмеження з requiredна, defaultLowі це спрацювало. Той самий код використовувався для збою на iOS 12.
Стівен Вандевеге,

52

Я хочу зробити невелике доповнення до відповіді Сірілли.

Якщо ви створюєте обмеження в коді, обов’язково встановіть його пріоритет, перш ніж активувати його. Наприклад:

surveyViewHeightConstraint = [NSLayoutConstraint constraintWithItem:self
                                               attribute:NSLayoutAttributeHeight
                                               relatedBy:NSLayoutRelationEqual
                                                  toItem:self.superview
                                               attribute:NSLayoutAttributeHeight
                                              multiplier:1
                                                constant:0];
surveyViewHeightConstraint.active = YES;
surveyViewHeightConstraint.priority = 999;

Це призведе до винятку під час виконання.

Мутація пріоритету з необхідного на не встановлене обмеження (або навпаки) не підтримується.

Правильний порядок:

surveyViewHeightConstraint.priority = 999;
surveyViewHeightConstraint.active = YES;

Для версії Swift 4+

constraintName.priority = UILayoutPriority(rawValue: 999)


8

Ми завжди справлялися з цим, не змінюючи константу обмеження, а лише пріоритет. Наприклад, у вашій ситуації є два обмеження висоти.

 heightConstraintOne (who's height is set in the storyboard at 150, and priority set at 750)
 heightConstraintTwo (who's height is set in the storyboard at 0, and priority set at 250)

якщо ви хочете приховати вигляд, ви:

heightConstraintTwo.priority = 999;

так само, якщо ви хочете показати вигляд:

heightConstraintTwo.priority = 250;

5
Класно, зрозумів: використовуйте 999 замість 1000. Дякую
brainray

3

Сподіваюся, цей сценарій комусь допоможе: у мене було два обмеження, що вони були протилежними один одному, я маю на увазі, що вони не могли бути задоволені одночасно, у конструкторі інтерфейсів один з них мав 1000 пріоритетів, а інший - менше 1000 пріоритетів. коли я змінив їх у коді, у мене сталася така помилка:

Припинення дії програми через невпійманий виняток "NSInternalInconsistentcyException", причина: "Мутація пріоритету з необхідного на не встановлене обмеження (або навпаки) не підтримується. Ви пройшли пріоритет 250, а існуючий пріоритет був 1000. '

тоді я просто ініціалізував їх у функції viewDidLoad за допомогою значень .defaultHigh та .defaultLow, і це вирішило мою проблему.


1

За даними NSLayoutConstraints classвсередині UIKit Module

Якщо рівень пріоритету обмеження менший за UILayoutPriorityRequired, це необов’язково. Обмеження вищого пріоритету виконуються перед обмеженнями нижчого пріоритету. Задоволення обмеження - це не все або нічого. Якщо обмеження 'a == b' є необов'язковим, це означає, що ми спробуємо мінімізувати 'abs (ab)'. Ця властивість може бути змінена лише в рамках початкового налаштування або за бажанням. Після додавання обмеження до подання буде видано виняток, якщо пріоритет змінити з / на NSLayoutPriorityRequired.

Приклад: - UIButtonобмеження з різними пріоритетами -

 func setConstraints() {
        buttonMessage.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint(item: buttonMessage, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1.0, constant: -10).isActive = true

        let leading = NSLayoutConstraint(item: buttonMessage, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1.0, constant: 10)

        leading.isActive = true


        let widthConstraint = NSLayoutConstraint(item: buttonMessage, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 100)

        let heightConstraint = NSLayoutConstraint(item: buttonMessage, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 50)


        let trailingToSuperView = NSLayoutConstraint(item: buttonMessage, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0)

        trailingToSuperView.priority = 999
        trailingToSuperView.isActive = true

        //leading.isActive = false//uncomment & check it will align to right of the View

        buttonMessage.addConstraints([widthConstraint,heightConstraint])

         }  

1
Ні, ніколи не слід створювати обмеження в viewDidLayoutSubviews. Цей метод можна викликати кілька разів, що може призвести до збою програми, якщо ви створите там дублікати обмежень.
миль на годину

0

Я стикався з тим же питанням. Оскільки згадана вище відповідь у iOS 13 зміна пріоритету буде працювати нормально, однак у iOS 12 це призведе до збою.

Я зміг вирішити цю проблему, створивши IBOutlet NSLayoutConstraint до цього конкретного обмеження в Storyboard, зберігаючи пріоритет до 1000, нижче наведено код виправлення.

if (Condition) {
    surveyViewHeightConstraint.constant = 0;
    surveyViewHeightConstraint.isActive = false;
} else if (index == 1) {
    surveyViewHeightConstraint.constant = 163;
    surveyViewHeightConstraint.isActive = True;
}

Сподіваюся, це допомагає !!! Ура


-3

Тепер ви можете просто взяти підключення IBOutlet для своїх обмежень, а потім використати цей код.

self.webviewHeight.priority = UILayoutPriority(rawValue: 1000)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.