Я использую Swift и хочу иметь возможность загружать UIViewController при повороте на альбомную ориентацию. Может ли кто-нибудь указать мне правильное направление?
Я ничего не могу найти в Интернете и немного смущен документацией.
Я использую Swift и хочу иметь возможность загружать UIViewController при повороте на альбомную ориентацию. Может ли кто-нибудь указать мне правильное направление?
Я ничего не могу найти в Интернете и немного смущен документацией.
Ответы:
Вот как я получил это работает:
В 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")
}
}
Надеюсь, это поможет кому-нибудь еще!
Спасибо!
selector
иметь формат строки "rotated:"
??
rotated()
это не так)
UIDeviceOrientation
это что-то отличное от UIInterfaceOrientation
... Это потому, что UIDeviceOrientation
также обнаруживает ориентацию лицевой стороной вниз и лицевой стороной вверх, что означает, что ваш код может случайным образом перемещаться между книжной и альбомной ориентацией, если ваше устройство лежит на почти плоской, но слегка неровной поверхности (т.е. покачивание на выступающей поверхности). камера
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")
}
}
Необходимо обнаружить вращение при использовании камеры с 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
. Вместо этого можно избежать замыкания, и теперь у вас есть решение, позволяющее избежать сбоя из-за вызова неверного селектора.
Swift 4.0
В Swift 4.0 Apple рекомендовала нам избегать использования #selector
, поэтому в этом подходе теперь используется блок завершения. Этот подход также обратно совместим со Swift 3.x и будет рекомендованным подходом в будущем.
Это предупреждение компилятора, которое вы получите в проекте Swift 4.x, если вы используете #selector
функцию из-за устаревания @objc
вывода:
Вступление в стремительную эволюцию по этому изменению .
Настройте обратный вызов:
// 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)
Использование -orientation
свойства of UIDevice
является неправильным (даже если оно может работать в большинстве случаев) и может привести к некоторым ошибкам, например, UIDeviceOrientation
учитывайте также ориентацию устройства, если оно направлено вверх или вниз, UIInterfaceOrientation
для перечисления нет прямой пары в перечислении. ценности.
Кроме того, если вы заблокируете свое приложение в какой-то определенной ориентации, UIDevice предоставит вам ориентацию устройства без учета этого.
С другой стороны iOS8 устарела interfaceOrientation
собственность на UIViewController
класс.
Для определения ориентации интерфейса доступно 2 варианта:
Чего еще не хватает, так это способа понять направление изменения ориентации интерфейса, что очень важно во время анимации.
На сессии 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)
}
}
Я знаю, что этот вопрос для 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
}
Просто, это работает в 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)
}
didRotateFromInterfaceOrientation()
не работает надежно. Он пропускает некоторые повороты. iewWillTransitionToSize:withTransitionCoordinator:
работает нормально
Используйте новый viewWillTransitionToSize (_: withTransitionCoordinator :)
Мне нравится проверять уведомление об ориентации, потому что вы можете добавить эту функцию в любой класс, не нужно быть представлением или контроллером представления. Даже в вашем приложении делегат.
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
}
В Задаче С
-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
В быстром
func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
Переопределите этот метод, чтобы обнаружить изменение ориентации.
Свифт 3 | Уведомление UIDeviceOrientationDidChange наблюдается слишком часто
Следующий код печатает «deviceDidRotate» каждый раз, когда ваше устройство меняет ориентацию в трехмерном пространстве - независимо от перехода из портретной в альбомную ориентацию. Например, если вы держите свой телефон в портретной ориентации и наклоняете его вперед и назад - 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")
}
}
}
Важные моменты, на которые следует обратить внимание:
unknown
ориентация есть.Надеюсь, кто-то найдет это полезным.
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)")
}
Если вы хотите сделать что-то ПОСЛЕ того, как вращение завершено, вы можете использовать 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`
})
}
Проверьте, изменилось ли вращение с: 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
}
}
willRotate
устарела, лучше использовать viewWillTransition
.
Свифт 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
}
}
Многие ответы не помогают, когда нужно обнаруживать различные контроллеры представления. Этот делает свое дело.
viewWillDisappear
и добавить addObserver
в viewDidLoad
. iOS отписывается от просмотра контроллера автоматически.
UIDevice.current.orientation.isFlat
Мой подход подобен тому, что показывает 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
}
}
Я использую, 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...
}
}
Для 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
}
}
UIDevice.current.orientation.isFlat
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
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
}
}
}
- (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.
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...
}
В iOS 13.1.2 ориентация всегда возвращает 0, пока устройство не будет повернуто. Мне нужно вызвать UIDevice.current.beginGeneratingDeviceOrientationNotifications (), чтобы получить фактическое вращение до того, как произойдет любое событие поворота.