Где я должен устанавливать ограничения автоопределения при программном создании представлений

Я вижу разные примеры, где установлены ограничения. Некоторые устанавливают их в viewDidLoad/loadView (после добавления subview). Другие устанавливают их в методе updateViewConstraints, который вызывается viewDidAppear.

Когда я пытаюсь установить ограничения в updateViewContraints, может возникнуть перегруженность макета, например. небольшая задержка перед представлением. Кроме того, если я использую этот метод, я должен сначала устранить существующие ограничения, т.е. [self.view [removeConstraints:self.view.constraints]?

Ответ 1

Я установил свои ограничения в viewDidLoad/loadView (я нацелился на iOS >= 6). updateViewConstraints полезен для изменения значений ограничений, например. если какое-то ограничение зависит от ориентации экрана (я знаю, это плохая практика), вы можете изменить его constant в этом методе.

Добавление ограничений в viewDidLoad показано во время сеанса "Введение в автоматическую компоновку для iOS и OS X" (WWDC 2012), начиная с 39:22. Я думаю, что это одна из тех вещей, которые говорят во время лекций, но не приземляются в документации.

ОБНОВЛЕНИЕ: Я заметил упоминание о настройке ограничений в Управление ресурсами в контроллерах просмотра:

Если вы предпочитаете создавать представления программно, вместо использования раскадровки, вы делаете это, переопределяя свои контроллеры просмотров loadViewметод. Ваша реализация этого метода должна сделать следующее:

(...)

3.Если вы используете автоматический макет, назначьте достаточные ограничения для каждого из только что созданные вами виды, чтобы управлять положением и размером вашего просмотры. В противном случае выполните viewWillLayoutSubviews и viewDidLayoutSubviews методы настройки фреймов подзонов в иерархию представлений. См. "Изменение размеров представлений диспетчера просмотров".

ОБНОВЛЕНИЕ 2: во время WWDC 2015 Apple дала новое объяснение updateConstraints и updateViewConstraints рекомендуемое использование

Действительно, все это способ взглядов иметь возможность вносить изменения в ограничения как раз вовремя для следующего прохода макета, но он часто не нужен.

Вся ваша начальная установка ограничения должна в идеале произойти внутри Interface Builder.

Или, если вы действительно обнаружите, что вам необходимо программно выделять свои ограничения, некоторое место, например viewDidLoad, намного лучше.

Ограничения на обновление действительно просто для работы, которая должна периодически повторяться.

Кроме того, довольно просто изменить ограничения, когда вы обнаружите необходимость сделать это; тогда как если вы возьмете эту логику отдельно от другого связанного с ней кода и переместите его в отдельный метод, который будет выполнен позже, ваш код станет намного сложнее следовать, поэтому вам будет сложнее поддерживать, для других людей будет намного сложнее понять.

Итак, когда вам нужно использовать ограничения на обновление?

Ну, это сводится к производительности.

Если вы обнаружите, что просто изменение ограничений на месте слишком медленное, то ограничения обновления могут помочь вам.

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

Причина этого в том, что движок способен обрабатывать все изменения ограничений, которые происходят в этом проходе, в виде пакета.

Ответ 2

Я рекомендую создать BOOL и установить их в -updateConstraints UIView (или -updateViewConstraints для UIViewController).

-[UIView updateConstraints]: (apple docs)

Пользовательские представления, которые сами устанавливают ограничения, должны сделать это, переопределив этот метод.

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

Например:

  - (void)updateConstraints {  // for view controllers, use -updateViewConstraints

         if (!_hasLoadedConstraints) {
              _hasLoadedConstraints = YES;
             // create your constraints
         }
         [super updateConstraints];
    }

Приветствуем @fresidue в комментариях, указав, что документы Apple рекомендуют вызывать super в качестве последнего шага. Если вы вызываете super, прежде чем вносить изменения в некоторые ограничения, вы можете столкнуться с исключительной ситуацией (crash).

Ответ 3

У меня есть это решение для изменения ограничений до того, как загружаются те, кто находится в раскадровке. Это решение устраняет любые задержки после загрузки представления.

-(void)updateViewConstraints{

    dispatch_async(dispatch_get_main_queue(), ^{

            //Modify here your Constraint -> Activate the new constraint and deactivate the old one

            self.yourContraintA.active = true;
            self.yourContraintB.active= false;
            //ecc..
           });

    [super updateViewConstraints]; // This must be the last thing that you do here -> if! ->Crash!
}

Ответ 4

Вы можете установить их в viewWillLayoutSubviews: тоже:

 override func viewWillLayoutSubviews() {

    if(!wasViewLoaded){
        wasViewLoaded = true

        //update constraint

        //also maybe add a subview            
    }
}

Ответ 5

Сделайте это с учетом метода подкомпоновки макета

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
}