Estoy usando Swift y quiero poder cargar un UIViewController cuando giro a horizontal, ¿alguien puede señalarme en la dirección correcta?
No puedo encontrar nada en línea y la documentación me confunde un poco.
Estoy usando Swift y quiero poder cargar un UIViewController cuando giro a horizontal, ¿alguien puede señalarme en la dirección correcta?
No puedo encontrar nada en línea y la documentación me confunde un poco.
Respuestas:
Así es como lo hice funcionar:
En AppDelegate.swift
el interior de la didFinishLaunchingWithOptions
función pongo:
NotificationCenter.default.addObserver(self, selector: #selector(AppDelegate.rotated), name: UIDevice.orientationDidChangeNotification, object: nil)
y luego dentro de la clase AppDelegate pongo la siguiente función:
func rotated() {
if UIDeviceOrientationIsLandscape(UIDevice.current.orientation) {
print("Landscape")
}
if UIDeviceOrientationIsPortrait(UIDevice.current.orientation) {
print("Portrait")
}
}
Espero que esto ayude a alguien más!
¡Gracias!
selector
tener un formato de cadena de "rotated:"
??
rotated()
no lo hace)
UIDeviceOrientation
es algo diferente a UIInterfaceOrientation
... Esto UIDeviceOrientation
también se debe a que detecta las orientaciones boca abajo y boca arriba, lo que significa que su código puede saltar aleatoriamente entre retrato y paisaje si su dispositivo descansa sobre una superficie casi plana pero ligeramente irregular (es decir, balanceándose sobre el saliente cámara de los 6 / 6s)
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")
}
}
Necesito detectar la rotación mientras uso la cámara AVFoundation
y descubrí que los métodos didRotate
( ahora obsoletos ) willTransition
no eran confiables para mis necesidades. El uso de la notificación publicada por David funcionó, pero no está actualizado para Swift 3.x / 4.x.
Swift 4.2 El nombre de la notificación ha sido cambiado.
El valor de cierre sigue siendo el mismo que 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")
}
}
Para configurar la notificación para Swift 4.2 :
NotificationCenter.default.addObserver(forName: UIDevice.orientationDidChangeNotification,
object: nil,
queue: .main,
using: didRotate)
Para eliminar la notificación de Swift 4.2 :
NotificationCenter.default.removeObserver(self,
name: UIDevice.orientationDidChangeNotification,
object: nil)
Con respecto a la declaración de desaprobación , mi comentario inicial fue engañoso, por lo que quería actualizar eso. Como se señaló, el uso de la @objc
inferencia ha quedado en desuso, lo que a su vez era necesario para usar a #selector
. Al usar un cierre, esto se puede evitar y ahora tiene una solución que debería evitar un bloqueo debido a llamar a un selector no válido.
Swift 4.0
Con Swift 4.0, Apple nos ha alentado a evitar el uso de #selector
, por lo que este enfoque utiliza un bloque de finalización ahora. Este enfoque también es retrocompatible con Swift 3.xy sería el enfoque recomendado en el futuro.
Esta es la advertencia del compilador que recibirá en un proyecto Swift 4.x si usa la #selector
función debido a la depreciación de la @objc
inferencia:
Entrada en rápida evolución en este cambio .
Configurar la devolución de llamada:
// 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")
}
}
Configurar la notificación:
NotificationCenter.default.addObserver(forName: .UIDeviceOrientationDidChange,
object: nil,
queue: .main,
using: didRotate)
Romper en pedazos:
NotificationCenter.default.removeObserver(self, name: .UIDeviceOrientationDidChange, object: nil)
El uso de la -orientation
propiedad de UIDevice
no es correcto (incluso si podría funcionar en la mayoría de los casos) y podría provocar algunos errores, por ejemplo, UIDeviceOrientation
considere también la orientación del dispositivo si está boca arriba o hacia abajo, no hay par directo en la UIInterfaceOrientation
enumeración para aquellos valores.
Además, si bloquea su aplicación en alguna orientación particular, UIDevice le dará la orientación del dispositivo sin tenerlo en cuenta.
Por otro lado, iOS8 ha dejado de usar la interfaceOrientation
propiedad en UIViewController
clase.
Hay 2 opciones disponibles para detectar la orientación de la interfaz:
Lo que aún falta es una forma de entender la dirección de un cambio de orientación de la interfaz, que es muy importante durante las animaciones.
En la sesión de WWDC 2014 "Ver avance del controlador en iOS8", el orador también proporciona una solución a ese problema, utilizando el método que reemplaza -will/DidRotateToInterfaceOrientation
.
Aquí la solución propuesta parcialmente implementada, más información aquí :
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)
}
}
Sé que esta pregunta es para Swift
, pero dado que es uno de los principales enlaces para una búsqueda en Google y si está buscando el mismo código en 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
}
Fácil, esto funciona en iOS8 y 9 / Swift 2 / Xcode7, solo ponga este código dentro de su viewcontroller.swift. Imprimirá las dimensiones de la pantalla con cada cambio de orientación, puede poner su propio código en su lugar:
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()
no funciona de manera confiable. Se echa de menos algunas rotaciones. iewWillTransitionToSize:withTransitionCoordinator:
funciona bien
Me gusta verificar la notificación de orientación porque puede agregar esta función en cualquier clase, no es necesario que sea una vista o un controlador de vista. Incluso en su delegado de aplicaciones.
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)
que almacenar en caché la notificación
@objc func orientationChanged(notification : NSNotification) {
//your code there
}
En el objetivo C
-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
En rápido
func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
Anule este método para detectar el cambio de orientación.
Swift 3 | UIDeviceOrientationDidChange Notificación observada con demasiada frecuencia
El siguiente código imprime "deviceDidRotate" cada vez que su dispositivo cambia de orientación en el espacio 3D, independientemente de un cambio de orientación vertical a horizontal. Por ejemplo, si sostiene su teléfono en orientación vertical y lo inclina hacia adelante y hacia atrás, se llama repetidamente deviceDidRotate ().
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(deviceDidRotate),
name: .UIDeviceOrientationDidChange,
object: nil
)
}
func deviceDidRotate() {
print("deviceDidRotate")
}
Para evitar esto, puede mantener la orientación anterior del dispositivo y verificar si hay un cambio en 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")
}
O puede usar una notificación diferente que solo se llama cuando el dispositivo cambia de horizontal a vertical. En este caso, querrás usar la UIApplicationDidChangeStatusBarOrientation
notificación.
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(deviceDidRotate),
name: .UIApplicationDidChangeStatusBarOrientation,
object: nil
)
}
func deviceDidRotate() {
print("deviceDidRotate")
}
Implementación funcional completa de cómo detectar cambios de orientación en Swift 3.0.
Elegí usar esta implementación porque las orientaciones telefónicas face up
y face down
eran importantes para mí, y quería que la vista cambiara solo una vez que supiera que la orientación estaba en la posición especificada.
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")
}
}
}
Las piezas importantes a tener en cuenta son:
unknown
a veces hay una orientación.Espero que alguien encuentre esto útil.
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)")
}
Si desea hacer algo DESPUÉS de que se complete la rotación, puede usar el UIViewControllerTransitionCoordinator
controlador de finalización de esta manera
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()
}
}
Desde iOS 8, esta es la forma correcta de hacerlo.
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`
})
}
Verifique si la rotación ha cambiado con: viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
Con el coordinator.animateAlongsideTransition(nil) { (UIViewControllerTransitionCoordinatorContext)
puede verificar si la transición ha finalizado.
Ver código a continuación:
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")
}
}
Aquí hay una manera fácil de detectar la orientación del dispositivo: ( 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
ahora está en desuso, mejor uso viewWillTransition
.
Swift 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
}
}
Muchas respuestas no ayudan cuando se necesita detectar en varios controladores de vista. Este hace el truco.
viewWillDisappear
y añadir addObserver
en viewDidLoad
. iOS cancela la vista del controlador de vista automáticamente.
UIDevice.current.orientation.isFlat
Mi enfoque es similar a lo que muestra bpedit arriba, pero con un enfoque iOS 9+. Quería cambiar el alcance del FSCalendar cuando la vista gira.
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)
}
Esto funcionó a continuación, pero me sentí avergonzado al respecto :)
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
}
}
Yo uso UIUserInterfaceSizeClass
para detectar una orientación cambiada en una UIViewController
clase así:
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...
}
}
Para 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
Configure la clase para recibir notificaciones de cambio de orientación del dispositivo:
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)
...
}
...
}
Código del controlador de configuración:
@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");
}
}
NOTA: Simplemente use este código para identificar que UIViewController está en qué orientación
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...
}
Con iOS 13.1.2, la orientación siempre devuelve 0 hasta que se gira el dispositivo. Necesito llamar a UIDevice.current.beginGeneratingDeviceOrientationNotifications () para obtener la rotación real antes de que ocurra cualquier evento de rotación.