Ответ
Для плавной анимации изменений layout при повороте устройства используйте UIViewControllerTransitionCoordinator, доступный в методе viewWillTransition(to:with:).
Стандартный подход:
override func viewWillTransition(to size: CGSize,
with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
// Сообщаем системе, что мы хотим выполнить анимацию вместе с системной анимацией поворота
coordinator.animate(alongsideTransition: { [weak self] context in
guard let self = self else { return }
// 1. Применяем изменения constraints (если используете Auto Layout)
self.updateConstraintsForOrientation()
// 2. Принудительно обновляем layout внутри анимационного блока
self.view.layoutIfNeeded()
// 3. Можем анимировать другие свойства (альфа, трансформацию)
self.headerView.alpha = (size.width > size.height) ? 0.8 : 1.0
}, completion: { [weak self] context in
// Действия после завершения системной анимации
if context.isCancelled {
print("Поворот отменен")
} else {
self?.finalizeLayoutAfterRotation()
}
})
}
Best practices и пояснения:
coordinator.animate(alongsideTransition:)— ключевой метод. Он синхронизирует вашу анимацию с системной.layoutIfNeeded()— обязательный вызов внутри блока анимации, чтобы изменения, вызванные активацией/деактивацией constraints или изменением frame, были анимированы.- Захват
[weak self]— критически важен для предотвращения retain cycles, так как coordinator может удерживать блок до завершения анимации. - Анимация через Auto Layout: Изменяйте
constantу constraints или активируйте/деактивируйте наборы constraints, затем вызывайтеlayoutIfNeeded(). - Проверка
isCancelledв completion — пользователь мог начать обратный поворот до завершения первой анимации.
Альтернатива для простых случаев: Если нужно лишь плавно обновить frame при повороте, убедитесь, что у вашего UIView установлено свойство autoresizingMask или используются корректные constraints — система анимирует это автоматически.