В 7.3/9/2 + Swift как отключить анимацию вращения, когда устройство вращается?

Этот вопрос строго касается iOS9 +

Скажем, у вас есть обычное современное приложение (автозапуск, раскадровка, универсальный), который позволяет все четыре положения вращения

введите описание изображения здесь

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

Но вы просто не хотите анимации NO во время вращения устройства. Вы хотите, чтобы это просто "click" к новому боковому или вертикальному расположению.

Единственный способ добиться этого - добавить:

override func viewWillTransitionToSize(size:CGSize,
       withTransitionCoordinator coordinator:UIViewControllerTransitionCoordinator)
    {
    coordinator.animateAlongsideTransition(nil, completion:
        {_ in
        UIView.setAnimationsEnabled(true)
        })
    UIView.setAnimationsEnabled(false)
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator);
    }

to один, самый высокий или почти самый высокий VC, который удерживает остальные виды контейнера или что-то еще в сцене.

Это в основном та же самая древняя идея использования willRotateToInterfaceOrientation/didRotateFromInterfaceOrientation (оба теперь непригодны для использования в современных iOS), чтобы включить анимацию.

Однако есть много проблем

  • это не работает AppWide, это беспорядок, он основан на сценах

  • Кажется, очень плохо просто отключить все анимации

  • вы можете увидеть все виды гоночных треков

Этот вопрос строго касается iOS9 +

В эти дни, есть ли лучший способ отключить анимацию вращения в приложении, которое поддерживает пейзаж/портрет???

Этот вопрос строго касается iOS9 +

Ответы

Ответ 1

Вы можете использовать метод swizzling.

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

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

extension UIViewController {

    public override static func initialize() {
        struct Static {
            static var token: dispatch_once_t = 0
        }

        dispatch_once(&Static.token) {
            let originalSelector = #selector(UIViewController.viewWillTransitionToSize(_:withTransitionCoordinator:))
            let swizzledSelector = #selector(UIViewController.genericViewWillTransitionToSize(_:withTransitionCoordinator:))

            let originalMethod = class_getInstanceMethod(self, originalSelector)
            let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)

            let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))

            if didAddMethod {
                class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
            } else {
                method_exchangeImplementations(originalMethod, swizzledMethod);
            }
        }
    }

    // MARK: - Method Swizzling
    func genericViewWillTransitionToSize(size:CGSize,
                                           withTransitionCoordinator coordinator:UIViewControllerTransitionCoordinator)
    {
        self.genericViewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
        coordinator.animateAlongsideTransition(nil, completion:
            {_ in
                UIView.setAnimationsEnabled(true)
        })
        UIView.setAnimationsEnabled(false)
    }
}

Ответ 2

Насколько я знаю, нет лучшего способа сделать это.

Хотя вы можете объявить отдельный класс с помощью этого метода и сделать все контроллеры представлений в своем приложении подклассами.

class NoRotateAnimationVC: UIViewController {
    override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
        UIView.setAnimationsEnabled(false)
        coordinator.notifyWhenInteractionEndsUsingBlock {_ in UIView.setAnimationsEnabled(true)}
    }
}

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

Вам нужно объявить этот новый класс один раз в своем приложении, а затем изменить все объявления своего контроллера представления от класса MyViewController: UIViewController до MyViewController: NoRotateAnimationVC.

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