Ответ
Основной метод — viewWillTransition(to:with:). Он предпочтительнее уведомлений, так как работает универсально на всех устройствах (включая iPad с многозадачностью).
Использование viewWillTransition(to:with:):
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
// size — новые размеры view контроллера
let isLandscape = size.width > size.height
// coordinator позволяет встроить свою анимацию в системную
coordinator.animate(alongsideTransition: { [weak self] _ in
// Анимируем изменения layout при повороте
self?.updateLayoutForOrientation(isLandscape: isLandscape)
}) { [weak self] _ in
// Действия после завершения анимации поворота
self?.logOrientationChange()
}
}
private func updateLayoutForOrientation(isLandscape: Bool) {
// Обновляем constraints или frames
someConstraint.constant = isLandscape ? 100 : 50
view.layoutIfNeeded() // Применяем изменения с анимацией
}
Альтернатива — уведомление (менее предпочтительно):
// Подписка (например, в viewDidLoad)
NotificationCenter.default.addObserver(
self,
selector: #selector(orientationDidChange),
name: UIDevice.orientationDidChangeNotification,
object: nil
)
@objc private func orientationDidChange() {
let orientation = UIDevice.current.orientation
// Обработка...
}
Почему viewWillTransition лучше?
- Универсальность: Срабатывает при любом изменении размера view (поворот, split view на iPad, изменение window size).
- Координация анимаций:
UIViewControllerTransitionCoordinatorпозволяет синхронизировать ваши анимации с системными. - Контроль: Вы получаете точные новые размеры (CGSize), а не абстрактную "ориентацию устройства".
Дополнительно: Для реагирования на изменение размеров, вызванное Auto Layout, также можно переопределить viewWillLayoutSubviews() или traitCollectionDidChange(_:) (для изменений trait collections, таких как size class).