Quiero agregar dos imágenes a la vista de una sola imagen (es decir, para una imagen horizontal y otra imagen para el retrato), pero no sé cómo detectar cambios de orientación usando idiomas rápidos.
Probé esta respuesta pero solo toma una imagen
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
if UIDevice.currentDevice().orientation.isLandscape.boolValue {
print("Landscape")
} else {
print("Portrait")
}
}
Soy nuevo en el desarrollo de iOS, ¡cualquier consejo sería muy apreciado!
Respuestas:
let const = "Background" //image name let const2 = "GreyBackground" // image name @IBOutlet weak var imageView: UIImageView! override func viewDidLoad() { super.viewDidLoad() imageView.image = UIImage(named: const) // Do any additional setup after loading the view. } override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) if UIDevice.current.orientation.isLandscape { print("Landscape") imageView.image = UIImage(named: const2) } else { print("Portrait") imageView.image = UIImage(named: const) } }
fuente
viewWillTransition
cuando hago subclasesUIView
?.isFlat
. Si solo desea capturar,portrait
le sugiero que cambie la cláusula else aelse if UIDevice.current.orientation.isPortrait
. Nota:.isFlat
puede suceder tanto en retrato como en paisaje, y con solo más {} estará predeterminado allí siempre (incluso si es plano).Usando NotificationCenter y UIDevice 's
beginGeneratingDeviceOrientationNotifications
Swift 4.2+
override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(ViewController.rotated), name: UIDevice.orientationDidChangeNotification, object: nil) } deinit { NotificationCenter.default.removeObserver(self, name: UIDevice.orientationDidChangeNotification, object: nil) } func rotated() { if UIDevice.current.orientation.isLandscape { print("Landscape") } else { print("Portrait") } }
Swift 3
override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(ViewController.rotated), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) } deinit { NotificationCenter.default.removeObserver(self) } func rotated() { if UIDevice.current.orientation.isLandscape { print("Landscape") } else { print("Portrait") } }
fuente
viewWillTransition:
anticipa que el cambio ocurrirá mientrasUIDeviceOrientationDidChange
se llama al uso una vez que se complete el cambio.shouldAutorotate
esté configurado enfalse
. Esto es útil para pantallas como la pantalla principal de la aplicación Cámara: la orientación está bloqueada pero los botones pueden girar.Swift 3 Código anterior actualizado:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) if UIDevice.current.orientation.isLandscape { print("Landscape") } else { print("Portrait") } }
fuente
⚠️ Orientación del dispositivo! = Orientación de la interfaz⚠️
Swift 5. * iOS14 y versiones anteriores
Realmente deberías marcar la diferencia entre:
Hay muchos escenarios en los que esos 2 valores no coinciden, como:
En la mayoría de los casos, querrá usar la orientación de la interfaz y puede obtenerla a través de la ventana:
private var windowInterfaceOrientation: UIInterfaceOrientation? { return UIApplication.shared.windows.first?.windowScene?.interfaceOrientation }
En caso de que también desee admitir <iOS 13 (como iOS 12), debe hacer lo siguiente:
private var windowInterfaceOrientation: UIInterfaceOrientation? { if #available(iOS 13.0, *) { return UIApplication.shared.windows.first?.windowScene?.interfaceOrientation } else { return UIApplication.shared.statusBarOrientation } }
Ahora necesita definir dónde reaccionar al cambio de orientación de la interfaz de la ventana. Hay varias formas de hacerlo, pero la solución óptima es hacerlo dentro
willTransition(to newCollection: UITraitCollection
.Este método UIViewController heredado, que se puede anular, se activará cada vez que cambie la orientación de la interfaz. En consecuencia, puede hacer todas sus modificaciones en este último.
Aquí hay un ejemplo de solución :
class ViewController: UIViewController { override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) { super.willTransition(to: newCollection, with: coordinator) coordinator.animate(alongsideTransition: { (context) in guard let windowInterfaceOrientation = self.windowInterfaceOrientation else { return } if windowInterfaceOrientation.isLandscape { // activate landscape changes } else { // activate portrait changes } }) } private var windowInterfaceOrientation: UIInterfaceOrientation? { return UIApplication.shared.windows.first?.windowScene?.interfaceOrientation } }
Al implementar este método, podrá reaccionar ante cualquier cambio de orientación de su interfaz. Pero tenga en cuenta que no se activará al abrir la aplicación, por lo que también tendrá que actualizar manualmente su interfaz en formato
viewWillAppear()
.Creé un proyecto de muestra que subraya la diferencia entre la orientación del dispositivo y la orientación de la interfaz. Además, le ayudará a comprender los diferentes comportamientos según el paso del ciclo de vida que decida actualizar su interfaz de usuario.
Siéntase libre de clonar y ejecutar el siguiente repositorio: https://github.com/wjosset/ReactToOrientation
fuente
func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator)
no funcionó. Lo hice funcionar usandofunc viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator)
.Swift 4+: estaba usando esto para el diseño de teclado virtual y, por alguna razón, el
UIDevice.current.orientation.isLandscape
método me decía que lo eraPortrait
, así que esto es lo que usé en su lugar:override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) if(size.width > self.view.frame.size.width){ //Landscape } else{ //Portrait } }
fuente
size
parámetro que se inyecta en viewWillTransitionToSize: withCoordinator: método que escribió anteriormente. Esto reflejará el tamaño exacto que tendrá su vista después de la transición.Swift 4.2, RxSwift
Si necesitamos volver a cargar collectionView.
NotificationCenter.default.rx.notification(UIDevice.orientationDidChangeNotification) .observeOn(MainScheduler.instance) .map { _ in } .bind(to: collectionView.rx.reloadData) .disposed(by: bag)
Rápido 4, RxSwift
Si necesitamos volver a cargar collectionView.
NotificationCenter.default.rx.notification(NSNotification.Name.UIDeviceOrientationDidChange) .observeOn(MainScheduler.instance) .map { _ in } .bind(to: collectionView.rx.reloadData) .disposed(by: bag)
fuente
Creo que la respuesta correcta es en realidad una combinación de ambos enfoques:
viewWIllTransition(toSize:)
yNotificationCenter
'sUIDeviceOrientationDidChange
.viewWillTransition(toSize:)
le notifica antes de la transición.NotificationCenter
UIDeviceOrientationDidChange
le notifica después .Tienes que ser muy cuidadoso. Por ejemplo,
UISplitViewController
cuando el dispositivo gira en ciertas orientaciones,DetailViewController
se saca de la matriz delUISplitViewController
'viewcontrollers
y se empuja al maestroUINavigationController
. Si busca el controlador de vista de detalles antes de que finalice la rotación, es posible que no exista y se bloquee.fuente
Si está utilizando la versión Swift> = 3.0, hay algunas actualizaciones de código que debe aplicar, como ya han dicho otros. No olvides llamar a super:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) // YOUR CODE OR FUNCTIONS CALL HERE }
Si está pensando en utilizar un StackView para sus imágenes, tenga en cuenta que puede hacer algo como lo siguiente:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) if UIDevice.current.orientation.isLandscape { stackView.axis = .horizontal } else { stackView.axis = .vertical } // else }
Si está utilizando Interface Builder, no olvide seleccionar la clase personalizada para este objeto UIStackView, en la sección Identity Inspector en el panel derecho. Luego simplemente cree (también a través de Interface Builder) la referencia de IBOutlet a la instancia personalizada de UIStackView:
@IBOutlet weak var stackView: MyStackView!
Toma la idea y adáptala a tus necesidades. ¡Espero que esto le pueda ayudar!
fuente
Rápido 4
Tuve algunos problemas menores al actualizar la vista ViewControllers usando
UIDevice.current.orientation
, como actualizar las restricciones de las celdas de la vista de tabla durante la rotación o animación de las subvistas.En lugar de los métodos anteriores, actualmente estoy comparando el tamaño de transición con el tamaño de la vista de los controladores de vista. Este parece ser el camino correcto a seguir, ya que uno tiene acceso a ambos en este punto del código:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) print("Will Transition to size \(size) from super view size \(self.view.frame.size)") if (size.width > self.view.frame.size.width) { print("Landscape") } else { print("Portrait") } if (size.width != self.view.frame.size.width) { // Reload TableView to update cell's constraints. // Ensuring no dequeued cells have old constraints. DispatchQueue.main.async { self.tableView.reloadData() } } }
Salida en un iPhone 6:
Will Transition to size (667.0, 375.0) from super view size (375.0, 667.0) Will Transition to size (375.0, 667.0) from super view size (667.0, 375.0)
fuente
Todas las contribuciones anteriores están bien, pero una pequeña nota:
a) si la orientación se establece en plist, solo retrato o ejemplo, no se le notificará a través de viewWillTransition
b) si de todos modos necesitamos saber si el usuario ha girado el dispositivo (por ejemplo, un juego o similar ..) solo podemos usar:
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.rotated), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
probado en Xcode8, iOS11
fuente
Puede usar
viewWillTransition(to:with:)
y tocaranimate(alongsideTransition:completion:)
para obtener la orientación de la interfaz DESPUÉS de que se complete la transición. Solo tiene que definir e implementar un protocolo similar a este para aprovechar el evento. Tenga en cuenta que este código se usó para un juego SpriteKit y su implementación específica puede diferir.protocol CanReceiveTransitionEvents { func viewWillTransition(to size: CGSize) func interfaceOrientationChanged(to orientation: UIInterfaceOrientation) }
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) guard let skView = self.view as? SKView, let canReceiveRotationEvents = skView.scene as? CanReceiveTransitionEvents else { return } coordinator.animate(alongsideTransition: nil) { _ in if let interfaceOrientation = UIApplication.shared.windows.first?.windowScene?.interfaceOrientation { canReceiveRotationEvents.interfaceOrientationChanged(to: interfaceOrientation) } } canReceiveRotationEvents.viewWillTransition(to: size) }
Puede establecer puntos de interrupción en estas funciones y observar que
interfaceOrientationChanged(to orientation: UIInterfaceOrientation)
siempre se llama despuésviewWillTransition(to size: CGSize)
con la orientación actualizada.fuente
Para obtener la orientación correcta al iniciar la aplicación , debe verificarla
viewDidLayoutSubviews()
. Otros métodos descritos aquí no funcionarán.Aquí tienes un ejemplo de cómo hacerlo:
var mFirstStart = true override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() if (mFirstStart) { mFirstStart = false detectOrientation() } } func detectOrientation() { if UIDevice.current.orientation.isLandscape { print("Landscape") // do your stuff here for landscape } else { print("Portrait") // do your stuff here for portrait } } override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { detectOrientation() }
Esto funcionará siempre, en el primer inicio de la aplicación y si gira mientras la aplicación se está ejecutando .
fuente
Otra forma de detectar las orientaciones de los dispositivos es con la función traitCollectionDidChange (_ :). El sistema llama a este método cuando cambia el entorno de la interfaz de iOS.
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) //... }
Además, puede usar la función willTransition (to: with :) (que se llama antes de traitCollectionDidChange (_ :)), para obtener información justo antes de que se aplique la orientación.
override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) { super.willTransition(to: newCollection, with: coordinator) //... }
fuente