Добавление, повторное использование и удаление NSLayoutAnchors

Итак, у меня есть вид контейнера (который стыкуется с краями экрана) и дочерний вид, который должен входить и выходить из него.

func slideOut() {
    UIView.animateWithDuration(Double(0.5), animations: {
        self.container.bottomAnchor
               .constraintEqualToAnchor(self.child.bottomAnchor).active = false
        self.view.layoutIfNeeded()
    })
}

func slideIn() {
    UIView.animateWithDuration(Double(0.5), animations: {
        self.container.bottomAnchor
               .constraintEqualToAnchor(self.child.bottomAnchor).active = true
        self.view.layoutIfNeeded()
    })
    print("numConstraints: \(container.constraints.count)")
}

Анимация slideIn() прекрасна, как и предполагалось. Проблема в том, что я не знаю, как сделать анимацию slideOut(). Если я просто деактивирую NSLayoutConstraint, как указано выше, ничего не произойдет. Если я попробую:

self.container.bottomAnchor
       .constraintEqualToAnchor(self.child.topAnchor).active = true

тогда появляется предупреждение о невозможности одновременного удовлетворения ограничений, и ничего не происходит визуально. Кроме того, всякий раз, когда я делаю активным NSLayoutConstraint, число ограничений (print(container.constraints.count)) увеличивается, что не может быть хорошо.

Итак, мои вопросы:

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

Ответ 1

Метод constraintEqualToAnchor создает новое ограничение. Поэтому, когда вы вызываете self.container.bottomAnchor.constraintEqualToAnchor(self.child.bottomAnchor) в функции выталкивания, вы не используете ограничение, добавленное в методе slideIn.

Чтобы добиться желаемой анимации скольжения, вам нужно будет сохранить ссылку на предыдущее ограничение. Я не уверен, что эффект установки свойства .active в ограничении будет в функции выталкивания, поскольку я не знаю, как настроена иерархия вашего представления. Но один из способов повторного использования ограничения будет содержать его как свойство var в вашем VC:

lazy var bottomConstraint:NSLayoutConstraint = self.container.bottomAnchor
        .constraintEqualToAnchor(self.child.bottomAnchor)

func slideOut() {
    UIView.animateWithDuration(Double(0.5), animations: {
        self.bottomConstraint.active = false
        self.view.layoutIfNeeded()
    })
}

func slideIn() {
    UIView.animateWithDuration(Double(0.5), animations: {
        self.bottomConstraint.active = true
        self.view.layoutIfNeeded()
    })
    print("numConstraints: \(container.constraints.count)")
}

Из Apple Docs:

Активация или деактивация вызовов ограничений addConstraint: и removeConstraint: в представлении, которое является ближайшим общим предком элементов, управляемых этим ограничением.

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