Как определить изменение ориентации?

Я использую Swift, и я хочу иметь возможность загружать UIViewController, когда я поворачиваюсь в альбом, может ли кто-нибудь указать мне в правильном направлении?

Я не могу найти что-либо в Интернете и немного смущен документации.

Ответ 1

Вот как я это получил:

В AppDelegate.swift внутри функции didFinishLaunchingWithOptions я вставил:

NotificationCenter.default.addObserver(self, selector: #selector(AppDelegate.rotated), name: UIDevice.orientationDidChangeNotification, object: nil)

а затем внутри класса AppDelegate я поместил следующую функцию:

func rotated() {
    if UIDeviceOrientationIsLandscape(UIDevice.current.orientation) {
        print("Landscape")
    }

    if UIDeviceOrientationIsPortrait(UIDevice.current.orientation) {
        print("Portrait")
    }
}

Надеюсь, это кому-нибудь еще поможет!

Спасибо!

Ответ 2

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    if UIDevice.current.orientation.isLandscape {
        print("Landscape")
    if UIDevice.current.orientation.isFlat {
        print("Flat")
    } else {
        print("Portrait")
    }
}

Ответ 3

Необходимо обнаружить вращение при использовании камеры с AVFoundation, и обнаружил, что didRotate (теперь устарели) и willTransition были ненадежными для моих нужд. Использование уведомления, опубликованного Дэвидом, сработало, но не актуально для Swift 3.x/4.x.

Swift 4.2 Имя уведомления было изменено.

Значение закрытия остается таким же, как Swift 4.0:

var didRotate: (Notification) -> Void = { notification in
        switch UIDevice.current.orientation {
        case .landscapeLeft, .landscapeRight:
            print("landscape")
        case .portrait, .portraitUpsideDown:
            print("Portrait")
        default:
            print("other")
        }
    }

Чтобы настроить уведомление для Swift 4.2:

NotificationCenter.default.addObserver(forName: UIDevice.orientationDidChangeNotification,
                                       object: nil,
                                       queue: .main,
                                       using: didRotate)

Чтобы снять уведомление для Swift 4.2:

NotificationCenter.default.removeObserver(self,
                                          name: UIDevice.orientationDidChangeNotification,
                                          object: nil)

Что касается заявления об устаревании, мой первоначальный комментарий вводил в заблуждение, поэтому я хотел обновить его. Как уже отмечалось, использование вывода @objc устарело, что, в свою очередь, было необходимо для использования #selector. Вместо этого можно избежать замыкания, и теперь у вас есть решение, которое должно избежать сбоя из-за вызова неверного селектора.

Все ниже здесь устарело с XCode 10 и iOS 4.2

Swift 4.0 В Swift 4.0 Apple рекомендовала нам не использовать #selector, поэтому в этом подходе теперь используется блок завершения. Этот подход также обратно совместим со Swift 3.x и будет рекомендованным подходом в будущем.

Это предупреждение компилятора, которое вы получите в проекте Swift 4.x, если будете использовать функцию #selector из-за @objc вывода @objc:

enter image description here

Вступление в стремительную эволюцию по этому изменению.

Настройте обратный вызов:

// If you do not use the notification var in your callback, 
// you can safely replace it with _
    var didRotate: (Notification) -> Void = { notification in
        switch UIDevice.current.orientation {
        case .landscapeLeft, .landscapeRight:
            print("landscape")
        case .portrait, .portraitUpsideDown:
            print("Portrait")
        default:
            print("other")
        }
    }

Настройте уведомление:

NotificationCenter.default.addObserver(forName: .UIDeviceOrientationDidChange,
                                       object: nil,
                                       queue: .main,
                                       using: didRotate)

Снеси его:

NotificationCenter.default.removeObserver(self, name: .UIDeviceOrientationDidChange, object: nil)

Ответ 4

Использование свойства -orientation свойства UIDevice неверно (даже если оно может работать в большинстве случаев) и может привести к некоторым ошибкам, например UIDeviceOrientation рассмотреть также ориентацию устройства, если оно находится лицом вверх или вниз, для этих значений нет прямой пары в UIInterfaceOrientation перечислении.
Кроме того, если вы заблокируете свое приложение в определенной ориентации, UIDevice предоставит вам ориентацию устройства, не принимая во внимание.
С другой стороны, iOS8 отказался от свойства interfaceOrientation в классе UIViewController.
Для определения ориентации интерфейса доступны 2 варианта:

  • Используйте ориентацию строки состояния
  • Используйте классы размера, на iPhone, если они не переопределены, они могут дать вам способ понять текущую ориентацию интерфейса

Что еще не хватает, это способ понять направление изменения ориентации интерфейса, что очень важно во время анимации.
В сессии WWDC 2014 "Просмотр прогресса контроллера в iOS8" динамик обеспечивает решение эта проблема тоже, используя метод, который заменяет -will/DidRotateToInterfaceOrientation.

Здесь предлагаемое решение частично реализовано, подробнее здесь:

func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
        let orientation = orientationFromTransform(coordinator.targetTransform())
        let oldOrientation = UIApplication.sharedApplication().statusBarOrientation
        myWillRotateToInterfaceOrientation(orientation,duration: duration)
        coordinator.animateAlongsideTransition({ (ctx) in
            self.myWillAnimateRotationToInterfaceOrientation(orientation,
            duration:duration)
            }) { (ctx) in
                self.myDidAnimateFromInterfaceOrientation(oldOrientation)
        }
    }

Ответ 5

Я знаю, что этот вопрос относится к Swift, но поскольку это одна из верхних ссылок для поиска Google, и если вы ищете тот же код в Objective-C:

// add the observer
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(rotated:) name:UIDeviceOrientationDidChangeNotification object:nil];

// remove the observer
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];

// method signature
- (void)rotated:(NSNotification *)notification {
    // do stuff here
}

Ответ 6

Просто, это работает в iOS8 и 9/Swift 2/Xcode7, просто поместите этот код в свой viewcontroller.swift. Он будет печатать размеры экрана при каждом изменении ориентации, вместо этого вы можете поместить свой собственный код:

override func didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation) {
        getScreenSize()
    }
    var screenWidth:CGFloat=0
    var screenHeight:CGFloat=0
    func getScreenSize(){
        screenWidth=UIScreen.mainScreen().bounds.width
        screenHeight=UIScreen.mainScreen().bounds.height
        print("SCREEN RESOLUTION: "+screenWidth.description+" x "+screenHeight.description)
    }

Ответ 8

В Objective C

-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator

В быстрой

func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)

Отмените этот метод для определения изменения ориентации.

Ответ 9

Swift 3 | Уведомление UIDeviceOrientationDidChange слишком часто наблюдается

Следующий код печатает "deviceDidRotate" каждый раз, когда ваше устройство меняет ориентацию в 3D-пространстве - независимо от изменения ориентации на портретную ориентацию. Например, если вы держите телефон в портретной ориентации и наклоняете его вперед и назад - deviceDidRotate() вызывается повторно.

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(
        self, 
        selector:  #selector(deviceDidRotate), 
        name: .UIDeviceOrientationDidChange, 
        object: nil
    )
}

func deviceDidRotate() {
    print("deviceDidRotate")
}

Чтобы обойти это, вы можете сохранить предыдущую ориентацию устройства и проверить изменение в deviceDidRotate().

var previousDeviceOrientation: UIDeviceOrientation = UIDevice.current.orientation

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(
        self, 
        selector:  #selector(deviceDidRotate), 
        name: .UIDeviceOrientationDidChange, 
        object: nil
    )
}

func deviceDidRotate() {
    if UIDevice.current.orientation == previousDeviceOrientation { return }
    previousDeviceOrientation = UIDevice.current.orientation
    print("deviceDidRotate")
}

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

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(
        self, 
        selector:  #selector(deviceDidRotate), 
        name: .UIApplicationDidChangeStatusBarOrientation, 
        object: nil
    )
}

func deviceDidRotate() {
    print("deviceDidRotate")
}

Ответ 10

override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) {
    //swift 3
    getScreenSize()
}


func getScreenSize(){
   let screenWidth = UIScreen.main.bounds.width
   let  screenHeight = UIScreen.main.bounds.height
    print("SCREEN RESOLUTION: \(screenWidth.description) x \(screenHeight.description)")
}

Ответ 11

Полная рабочая реализация, как определить изменение ориентации в Swift 3.0.

Я решил использовать эту реализацию, потому что ориентация телефона face up и face down была важна для меня, и я хотел, чтобы представление изменилось только после того, как я знал, что ориентация находится в указанной позиции.

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        //1
        NotificationCenter.default.addObserver(self, selector: #selector(deviceOrientationDidChange), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)

    }

    deinit {
        //3
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
    }

    func deviceOrientationDidChange() {
        //2
        switch UIDevice.current.orientation {
        case .faceDown:
            print("Face down")
        case .faceUp:
            print("Face up")
        case .unknown:
            print("Unknown")
        case .landscapeLeft:
            print("Landscape left")
        case .landscapeRight:
            print("Landscape right")
        case .portrait:
            print("Portrait")
        case .portraitUpsideDown:
            print("Portrait upside down")
        }
    }

}

Важные примечания:

  • Вы слушаете поток уведомлений DeviceOrientationDidChange и привязываете его к функции deviceOrientationDidChange
  • Затем вы включаете ориентацию устройства, не забудьте заметить, что существует ориентация unknown.
  • Как и любое уведомление, перед запуском viewController не забудьте следить за потоком уведомлений.

Надеюсь, что кто-то найдет это полезным.

Ответ 12

Мне нравится проверять уведомление об ориентации, потому что вы можете добавить эту функцию в любой класс, не нужно быть представлением или контроллером представления. Даже в вашем приложении делегат.

SWIFT 5:

    //ask the system to start notifying when interface change
    UIDevice.current.beginGeneratingDeviceOrientationNotifications()
    //add the observer
    NotificationCenter.default.addObserver(
        self,
        selector: #selector(orientationChanged(notification:)),
        name: UIDevice.orientationDidChangeNotification,
        object: nil)

чем кэширование уведомления

    @objc func orientationChanged(notification : NSNotification) {
        //your code there
    }

Ответ 13

Проверьте, изменилось ли вращение с помощью: viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)

С помощью coordinator.animateAlongsideTransition(nil) { (UIViewControllerTransitionCoordinatorContext) вы можете проверить, завершен ли переход.

Смотрите код ниже:

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {

    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)

    coordinator.animateAlongsideTransition(nil) { (UIViewControllerTransitionCoordinatorContext) in
        // if you want to execute code after transition finished
        print("Transition finished")
    }

    if size.height < size.width {
        // Landscape
        print("Landscape")
    } else {
        // Portrait
        print("Portrait")
    }

}

Ответ 14

Вот простой способ определить ориентацию устройства: (Swift 3)

override func willRotate(to toInterfaceOrientation: UIInterfaceOrientation, duration: TimeInterval) {
            handleViewRotaion(orientation: toInterfaceOrientation)
        }

    //MARK: - Rotation controls
    func handleViewRotaion(orientation:UIInterfaceOrientation) -> Void {
        switch orientation {
        case .portrait :
            print("portrait view")
            break
        case .portraitUpsideDown :
            print("portraitUpsideDown view")
            break
        case .landscapeLeft :
            print("landscapeLeft view")
            break
        case .landscapeRight :
            print("landscapeRight view")
            break
        case .unknown :
            break
        }
    }

Ответ 15

Если вы хотите сделать что-то ПОСЛЕ завершения вращения, вы можете использовать обработчик завершения UIViewControllerTransitionCoordinator, подобный этому

public override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)

    // Hook in to the rotation animation completion handler
    coordinator.animate(alongsideTransition: nil) { (_) in
        // Updates to your UI...
        self.tableView.reloadData()
    }
}

Ответ 16

Начиная с iOS 8 это правильный способ сделать это.

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)

    coordinator.animate(alongsideTransition: { context in
        // This is called during the animation
    }, completion: { context in
        // This is called after the rotation is finished. Equal to deprecated 'didRotate'
    })
}

Ответ 17

Свифт 4:

override func viewWillAppear(_ animated: Bool) {
    NotificationCenter.default.addObserver(self, selector: #selector(deviceRotated), name: UIDevice.orientationDidChangeNotification, object: nil)
}

override func viewWillDisappear(_ animated: Bool) {
    NotificationCenter.default.removeObserver(self, name: UIDevice.orientationDidChangeNotification, object: nil)
}

@objc func deviceRotated(){
    if UIDevice.current.orientation.isLandscape {
        //Code here
    } else {
        //Code here
    }
}

Многие ответы не помогают, когда нужно обнаружить через различные контроллеры представления. Этот делает свое дело.

Ответ 18

Мой подход аналогичен тому, что показано bpedit выше, но с фокусом iOS 9+. Я хочу изменить область FSCalendar при повороте представления.

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)

    coordinator.animateAlongsideTransition({ (context) in
        if size.height < size.width {
            self.calendar.setScope(.Week, animated: true)
            self.calendar.appearance.cellShape = .Rectangle
        }
        else {
            self.calendar.appearance.cellShape = .Circle
            self.calendar.setScope(.Month, animated: true)

        }

        }, completion: nil)
}

Это ниже работало, но я чувствовал себя застенчивым:)

coordinator.animateAlongsideTransition({ (context) in
        if size.height < size.width {
            self.calendar.scope = .Week
            self.calendar.appearance.cellShape = .Rectangle
        }
        }) { (context) in
            if size.height > size.width {
                self.calendar.scope = .Month
                self.calendar.appearance.cellShape = .Circle
            }
    }

Ответ 19

Я использую UIUserInterfaceSizeClass для определения ориентации, измененной в классе UIViewController, как это:

override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {

    let isiPadLandscapePortrait = newCollection.horizontalSizeClass == .regular && newCollection.verticalSizeClass == .regular
    let isiPhonePlustLandscape = newCollection.horizontalSizeClass == .regular && newCollection.verticalSizeClass == .compact
    let isiPhonePortrait = newCollection.horizontalSizeClass == .compact && newCollection.verticalSizeClass == .regular
    let isiPhoneLandscape = newCollection.horizontalSizeClass == .compact && newCollection.verticalSizeClass == .compact

     if isiPhonePortrait {
         // do something...
     }
}

Ответ 20

Для Swift 3

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    if UIDevice.current.orientation.isLandscape {
        //Landscape
    }
    else if UIDevice.current.orientation.isFlat {
        //isFlat
    }
    else {
        //Portrait
    }
}

Ответ 21

- (void)viewDidLoad {
  [super viewDidLoad];
  [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(OrientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil];
}

-(void)OrientationDidChange:(NSNotification*)notification {
  UIDeviceOrientation Orientation=[[UIDevice currentDevice]orientation];

  if(Orientation==UIDeviceOrientationLandscapeLeft || Orientation==UIDeviceOrientationLandscapeRight) {
    NSLog(@"Landscape");
  } else if(Orientation==UIDeviceOrientationPortrait) {
    NSLog(@"Potrait Mode");
  }
}

ПРИМЕЧАНИЕ. Просто используйте этот код для идентификации UIViewController, в котором ориентация

Ответ 22

override func viewDidLoad() {
    NotificationCenter.default.addObserver(self, selector: #selector(MyController.rotated), name: UIDevice.orientationDidChangeNotification, object: nil)
//...
}

@objc
private func rotated() {
    if UIDevice.current.orientation.isLandscape {

    } else if UIDevice.current.orientation.isPortrait {

    }

    //or you can check orientation separately UIDevice.current.orientation
    //portrait, portraitUpsideDown, landscapeLeft, landscapeRight... 

}

Ответ 23

Swift 5

Класс настройки для получения уведомлений об изменении ориентации устройства:

class MyClass {

    ...

    init (...) {

        ...

        super.init(...)

        // subscribe to device orientation change notifications
        UIDevice.current.beginGeneratingDeviceOrientationNotifications()
        NotificationCenter.default.addObserver(self, selector: #selector(orientationChanged), name: UIDevice.orientationDidChangeNotification, object: nil)

        ...

    }

    ...

}

Код обработчика установки:

@objc extension MyClass {
    func orientationChanged(_ notification: NSNotification) {
        let device = notification.object as! UIDevice
        let deviceOrientation = device.orientation

        if let connection = previewLayer.connection {
            switch deviceOrientation {
            case .landscapeLeft:   //do something for landscape left
            case .landscapeRight:  //do something for landscape right
            case .portrait:        //do something for portrait
            case .portraitUpsideDown: //do something for portrait upside-down 
            case .faceDown:        //do something for face down
            case .faceUp:          //do something for face up
            case .unknown:         //handle unknown
            @unknown default:      //handle unknown default
            }
        }
    }
}

Ответ 24

В iOS 13.1.2 ориентация всегда возвращает 0, пока устройство не будет повернуто. Мне нужно вызвать UIDevice.current.beginGeneratingDeviceOrientationNotifications(), чтобы получить фактическое вращение до того, как произойдет любое событие поворота.