Как анимировать изменение Auto Layout constraints в UIKit?

Ответ

Чтобы анимировать изменения Auto Layout constraints, необходимо изменить их свойства (например, constant, priority, isActive), а затем вызвать обновление layout внутри блока анимации UIView.animate.

Базовый алгоритм:

  1. Вне блока анимации измените нужные параметры констрейнтов.
  2. Внутри блока анимации вызовите layoutIfNeeded() для вью, чей layout нужно обновить (обычно это superview).

Пример: анимация высоты кнопки.

// 1. Есть @IBOutlet на констрейнт
@IBOutlet weak var buttonHeightConstraint: NSLayoutConstraint!

// 2. Функция, запускающая анимацию
func animateButtonExpansion() {
    // Изменяем константу ВНЕ блока анимации
    buttonHeightConstraint.constant = 150

    // Запускаем анимацию обновления layout
    UIView.animate(withDuration: 0.5, 
                   delay: 0.0, 
                   usingSpringWithDamping: 0.6, 
                   initialSpringVelocity: 0.2, 
                   options: .curveEaseInOut) {
        // 3. Вызываем layoutIfNeeded() ВНУТРИ блока анимации
        self.view.layoutIfNeeded() // Анимирует все pending changes layout
    }
}

Ключевые моменты:

  • layoutIfNeeded(): Этот метод заставляет систему немедленно вычислить и применить все ожидающие изменения layout, и именно это вычисление анимируется.
  • Что можно анимировать: constant, активацию/деактивацию констрейнтов (isActive), изменение priority (с осторожностью).
  • Для сложных анимаций: Используйте UIViewPropertyAnimator для интерактивных или паузируемых анимаций.
  • Производительность: Анимация изменений констрейнтов через layoutIfNeeded() обычно высокооптимизирована и предпочтительнее, чем ручное изменение frame.

Ответ 18+ 🔞

Да ты посмотри, какие тонкости, блядь! Анимировать констрейнты — это ж не просто так, пальцем в небо ткнуть. Тут, сука, целый ритуал, как в храме, только вместо молитв — layoutIfNeeded().

Так, слушай сюда, а не то в рот меня чих-пых! Чтобы эта ваша Auto Layout шевелить начала, надо не просто цифры поменять, а ещё и систему, блядь, вежливо попросить пересчитать всё это безобразие плавненько.

Как это, блядь, работает, по шагам:

  1. Сначала ты, сука, где-то в сторонке, тихонечко, меняешь свои констрейнты. Константу там, или isActive переключаешь — делаешь, что хочешь, но вне блока анимации. Пока ещё ничего не двигается.
  2. А потом, блядь, заходишь в этот самый священный UIView.animate, и там уже командуешь: «Так, пацаны, layoutIfNeeded()!». И вот тогда вся магия и начинается.

Вот тебе живой пример, чтоб не быть мудаком, который просто теорию гонит:

// 1. Привязали констрейнт высоты кнопки, как честные люди
@IBOutlet weak var buttonHeightConstraint: NSLayoutConstraint!

// 2. Функция, которая эту кнопку раздует
func animateButtonExpansion() {
    // Меняем константу ТУТ, снаружи! Типа готовим почву.
    buttonHeightConstraint.constant = 150

    // А теперь, сука, магия!
    UIView.animate(withDuration: 0.5,
                   delay: 0.0,
                   usingSpringWithDamping: 0.6,
                   initialSpringVelocity: 0.2,
                   options: .curveEaseInOut) {
        // 3. Главный фокус! Заставляем вьюху пересчитать свой лейаут.
        self.view.layoutIfNeeded() // Вот это и будет анимироваться, ёпта!
    }
}

На что смотреть, чтобы не обосраться:

  • layoutIfNeeded() — это волшебный пендель. Без него твои изменения просто бахнутся на экран в следующем цикле обновления, без всякой анимации. А с ним — плавненько так, красиво.
  • Что крутить можно: В основном constant. isActive тоже прокатит. priority — осторожнее, там можно и косяк получить недетский.
  • Если хочешь поизвращаться: Есть ещё UIViewPropertyAnimator — для анимаций, которые надо паузить, отматывать или пальцем тыкать. Мощная штука, но и мозг выносит конкретно.
  • И главное, блядь: Так делать — это правильно и оптимизировано. Это система сама всё просчитает. Куда лучше, чем вручную frame тыкать, как в старые добрые времена, когда деревья были большими, а код — говном.