Как обнаружить изменение ориентации?
Я использую Swift, и я хочу иметь возможность загружать UIViewController, когда я поворачиваюсь к ландшафту, может ли кто-нибудь указать мне в правильном направлении?
Я ничего не могу найти в интернете и немного запутался в документации.
20 ответов:
вот как я получил это работает:
на
AppDelegate.swift
внутри Я:NotificationCenter.default.addObserver(self, selector: #selector(AppDelegate.rotated), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
а затем внутри класса AppDelegate я поставил следующую функцию:
func rotated() { if UIDeviceOrientationIsLandscape(UIDevice.current.orientation) { print("Landscape") } if UIDeviceOrientationIsPortrait(UIDevice.current.orientation) { print("Portrait") } }
надеюсь, это поможет кому-нибудь еще!
спасибо!
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { if UIDevice.current.orientation.isLandscape { print("Landscape") } else { print("Portrait") } }
необходимо обнаружить вращение при использовании камеры с
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.х & бы быть рекомендуемый подход для продвижения вперед.это предупреждение компилятора, которое вы получите в Swift 4.проект X если вы используете
#selector
функция должная к осуждение@objc
вывод:запись в swift-evolution об этом изменении.
настройка вызова:
// 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)
Swift 3.0 это было мое предыдущее решение, но я бы посоветовал использовать решение 4.0 выше:
настройка уведомления (уведомления имя является недействительным в Свифт-4.2):
NotificationCenter.default.addObserver(self, selector: #selector(rotated), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
ответ на уведомление:
func rotated() { switch UIDevice.current.orientation { case .landscapeLeft, .landscapeRight: print("landscape") default: print("Portrait") } }
сорвать уведомление (имя уведомления недопустимо в Swift 4.2):
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
используя
-orientation
собственностьUIDevice
не правильно (даже если это может работать в большинстве случаев) и может привести к некоторым ошибкам, напримерUIDeviceOrientation
рассмотрим также ориентацию устройства, если оно обращено вверх или вниз, нет прямой пары вUIInterfaceOrientation
enum для этих значений.
Кроме того, если вы заблокируете свое приложение в определенной ориентации, UIDevice предоставит вам ориентацию устройства без учета этого.
С другой стороны iOS8 устарелinterfaceOrientation
недвижимость наUIViewController
класса.
Существует 2 варианта определения ориентации интерфейса:
- используйте ориентацию строки состояния
- используйте классы размера, на iPhone, если они не переопределены, они могут дать вам способ понять текущую ориентацию интерфейса
то, что все еще отсутствует, - это способ понять направление изменения ориентации интерфейса, что очень важно во время анимации.
в сессии WWDC 2014 "View controller advancement in 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) } }
легко, это работает в iOS8 и 9 / Swift 2 / Xcode7, просто поместите этот код внутри вашего viewcontroller.быстрый. Он будет печатать размеры экрана с каждым изменением ориентации, вы можете поместить свой собственный код вместо:
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) }
использовать новый viewWillTransitionToSize (_: withTransitionCoordinator:)
Я знаю, что этот вопрос является для
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 }
В Объективе C
-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
быстро
func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
переопределите этот метод для обнаружения изменения ориентации.
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") }
полная рабочая реализация способа обнаружения изменения ориентации в 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 обязательно прекратите наблюдение за потоком уведомлений.
надеюсь, кто-то найдет это полезным.
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)") }
Проверьте, изменилось ли вращение с помощью:
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") } }
вот простой способ определить ориентацию устройства: ( 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 } }
мне нравится проверять уведомление об ориентации, потому что вы можете добавить эту функцию в любой класс, не нужно быть видом или контроллером вида. Даже в вашем делегате приложения.
//ask the system to start notifying when interface change UIDevice.currentDevice().beginGeneratingDeviceOrientationNotifications() //add the observer NSNotificationCenter.defaultCenter().addObserver( self, selector: #selector(self.orientationChanged(_:)), name: UIDeviceOrientationDidChangeNotification, object: nil)
чем кэширование уведомление
func orientationChanged(notification : NSNotification) { //your code there }
мой подход похож на то, что 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 } }
Для Swift 3
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { if UIDevice.current.orientation.isLandscape { //Landscape } else { //Portrait } }
Я использую
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... } }
Если вы хотите что-то сделать после завершения вращения, вы можете использовать
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() } }
Так как 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` }) }
- (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 находится в какой ориентации