ios - color - ¿Cómo detectar el cambio de orientación?
ionic header color (20)
Estoy usando Swift y quiero cargar un UIViewController cuando gire en horizontal, ¿alguien puede indicarme la dirección correcta?
No puedo encontrar nada en línea y un poco confundido por la documentación.
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
}
}
Así es como lo hice funcionar:
En AppDelegate.swift
dentro de la función didFinishLaunchingWithOptions
puse:
NotificationCenter.default.addObserver(self, selector: #selector(AppDelegate.rotated), name: NSNotification.Name.UIDeviceOrientationDidChange, 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 los demás!
¡Gracias!
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`
})
}
El uso de la propiedad -orientation
de UIDevice
no es correcto (incluso si pudiera funcionar en la mayoría de los casos) y podría dar lugar a algunos errores, por ejemplo, UIDeviceOrientation
también considera la orientación del dispositivo si está boca arriba o hacia abajo, no hay par directo en UIInterfaceOrientation
enum para esos valores.
Además, si bloquea su aplicación en alguna orientación particular, UIDevice le dará la orientación del dispositivo sin tener eso en cuenta.
Por otro lado, iOS8 ha dejado de utilizar la propiedad interfaceOrientation
en la clase UIViewController
.
Hay 2 opciones disponibles para detectar la orientación de la interfaz:
- Usa la orientación de la barra de estado
- Use clases de tamaño, en iPhone si no se anulan, podrían darle una forma de entender la orientación actual de la interfaz
Lo que aún falta es una forma de entender la dirección de un cambio en la 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 hablante también proporciona una solución a ese problema, utilizando el método que reemplaza -will/DidRotateToInterfaceOrientation
.
Aquí la solución propuesta se implementó parcialmente, más información here :
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)
}
}
En el objetivo C
-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
En veloz
func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
Anule este método para detectar el cambio de orientación.
Fácil, esto funciona en iOS8 y 9 / Swift 2 / Xcode7, simplemente coloca este código dentro de tu viewcontroller.swift. Imprimirá las dimensiones de la pantalla con cada cambio de orientación, en su lugar puede poner su propio código:
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)
}
Me gusta verificar la notificación de orientación porque puede agregar esta característica en cualquier clase, no necesita ser una vista o un controlador de vista. Incluso en tu aplicación delegada.
//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)
que almacenar en caché la notificación
func orientationChanged(notification : NSNotification) {
//your code there
}
Mi enfoque es similar a lo que muestra bpedit arriba, pero con un enfoque iOS 9+. Quería cambiar el alcance de 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 a continuación funcionó, pero me sentí tímido 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
}
}
Necesito detectar la rotación mientras uso la cámara con AVFoundation
, y descubrí que los didRotate
( ahora obsoleto ) y willTransition
no eran confiables para mis necesidades. Usar la notificación publicada por David sí funcionó, pero no es actual para Swift 3.x / 4.x.
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 compatible con Swift 3.x y sería el enfoque recomendado en el futuro.
Esta es la advertencia del compilador que recibirá en un proyecto de Swift 4.x si usa la función #selector
:
Entrada en rápida evolución sobre 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")
}
}
Configura 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)
Swift 3.0 Esta fue mi solución anterior, pero recomendaría usar la solución 4.0 anterior:
Configura la notificación:
NotificationCenter.default.addObserver(self, selector: #selector(rotated), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
Responda a la notificación:
func rotated() {
switch UIDevice.current.orientation {
case .landscapeLeft, .landscapeRight:
print("landscape")
default:
print("Portrait")
}
}
Destruye la notificación:
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
Sé que esta pregunta es para Swift
, pero ya que es uno de los principales enlaces para una búsqueda en Google y si buscas 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
}
Si desea hacer algo DESPUÉS de completar la rotación, puede usar el UIViewControllerTransitionCoordinator
finalización UIViewControllerTransitionCoordinator
como este
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()
}
}
Uso UIUserInterfaceSizeClass
para detectar una orientación modificada en una clase UIViewController
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...
}
}
Verifique si la rotación ha cambiado con: viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
Con coordinator.animateAlongsideTransition(nil) { (UIViewControllerTransitionCoordinatorContext)
puede verificar si la transición ha finalizado.
Vea el 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")
}
}
Implementación completa de trabajo de cómo detectar cambios de orientación en Swift 3.0.
Elegí usar esta implementación porque las orientaciones del teléfono face up
y face down
eran importantes para mí, y quería que la vista cambiara solo cuando 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:
- Escucha la transmisión de notificación DeviceOrientationDidChange y la vincula a la función deviceOrientationDidChange
- Luego, enciende la orientación del dispositivo, asegúrese de tener en cuenta que a veces hay una orientación
unknown
. - Como cualquier notificación, antes de que viewController esté desinicializado, asegúrese de dejar de observar el flujo de notificaciones.
Espero que alguien encuentre esto útil.
Para Swift 3
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
if UIDevice.current.orientation.isLandscape {
//Landscape
}
else {
//Portrait
}
}
Swift 3 | Notificación de UIDeviceOrientationDidChange 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 mantiene el teléfono en orientación vertical e inclínelo 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 solucionar este problema, puede mantener la orientación del dispositivo anterior y comprobar si hay algún 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 recibe una llamada cuando el dispositivo cambia de horizontal a vertical. En este caso, querrá utilizar la notificación UIApplicationDidChangeStatusBarOrientation
.
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(deviceDidRotate),
name: .UIApplicationDidChangeStatusBarOrientation,
object: nil
)
}
func deviceDidRotate() {
print("deviceDidRotate")
}
- (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: Solo use este código para identificar a UIViewController en qué orientación
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)")
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
if UIDevice.current.orientation.isLandscape {
print("Landscape")
} else {
print("Portrait")
}
}