Sto usando Swift e voglio essere in grado di caricare un UIViewController quando giro in orizzontale, qualcuno può indicarmi la giusta direzione?
Non riesco a trovare nulla online e un po 'confuso dalla documentazione.
Sto usando Swift e voglio essere in grado di caricare un UIViewController quando giro in orizzontale, qualcuno può indicarmi la giusta direzione?
Non riesco a trovare nulla online e un po 'confuso dalla documentazione.
Risposte:
Ecco come l'ho fatto funzionare:
Nel AppDelegate.swiftall'interno della didFinishLaunchingWithOptions funzione ho messo:
NotificationCenter.default.addObserver(self, selector: #selector(AppDelegate.rotated), name: UIDevice.orientationDidChangeNotification, object: nil)
e poi all'interno della classe AppDelegate ho inserito la seguente funzione:
func rotated() {
if UIDeviceOrientationIsLandscape(UIDevice.current.orientation) {
print("Landscape")
}
if UIDeviceOrientationIsPortrait(UIDevice.current.orientation) {
print("Portrait")
}
}
Spero che questo aiuti chiunque altro!
Grazie!
selectoravere un formato stringa di "rotated:"??
rotated()non lo fanno)
UIDeviceOrientationè qualcosa di diverso da UIInterfaceOrientationquesto. Questo perché UIDeviceOrientationrileva anche gli orientamenti a faccia in giù e a faccia in su, il che significa che il tuo codice può saltare tra ritratto e paesaggio in modo casuale se il tuo dispositivo poggia su una superficie quasi piatta ma leggermente irregolare (ad esempio oscillando sulla sporgenza camera dei 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")
}
}
Ho bisogno di rilevare la rotazione durante l'utilizzo della fotocamera AVFoundatione ho scoperto che i metodi didRotate( ora deprecati ) e willTransitionnon erano affidabili per le mie esigenze. L'uso della notifica pubblicata da David ha funzionato, ma non è attuale per Swift 3.x / 4.x.
Swift 4.2 Il nome della notifica è stato modificato.
Il valore di chiusura rimane lo stesso di 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")
}
}
Per impostare la notifica per Swift 4.2 :
NotificationCenter.default.addObserver(forName: UIDevice.orientationDidChangeNotification,
object: nil,
queue: .main,
using: didRotate)
Per eliminare la notifica per Swift 4.2 :
NotificationCenter.default.removeObserver(self,
name: UIDevice.orientationDidChangeNotification,
object: nil)
Per quanto riguarda la dichiarazione di deprecazione , il mio commento iniziale era fuorviante, quindi volevo aggiornarlo. Come notato, l'uso @objcdell'inferenza è stato deprecato, che a sua volta era necessario per usare a #selector. Usando invece una chiusura, questo può essere evitato e ora hai una soluzione che dovrebbe evitare un arresto anomalo a causa della chiamata di un selettore non valido.
Swift 4.0
Con Swift 4.0, Apple ci ha incoraggiato a evitare di usare il #selector, quindi questo approccio ora utilizza un blocco di completamento. Questo approccio è anche retrocompatibile con Swift 3.x e sarebbe l'approccio raccomandato in futuro.
Questo è l'avviso del compilatore che riceverai in un progetto Swift 4.x se usi la #selectorfunzione a causa della deprecazione @objcdell'inferenza:
Entrata in rapida evoluzione su questo cambiamento .
Imposta il callback:
// 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")
}
}
Imposta la notifica:
NotificationCenter.default.addObserver(forName: .UIDeviceOrientationDidChange,
object: nil,
queue: .main,
using: didRotate)
Abbattilo:
NotificationCenter.default.removeObserver(self, name: .UIDeviceOrientationDidChange, object: nil)
L'uso della -orientationproprietà di UIDevicenon è corretto (anche se potrebbe funzionare nella maggior parte dei casi) e potrebbe portare ad alcuni bug, ad esempio UIDeviceOrientationprendere in considerazione anche l'orientamento del dispositivo se è rivolto verso l'alto o verso il basso, non esiste alcuna coppia diretta in UIInterfaceOrientationenum per quelli valori.
Inoltre, se blocchi l'app in un determinato orientamento, UIDevice ti fornirà l'orientamento del dispositivo senza tenerne conto.
D'altra parte iOS8 ha deprecato la interfaceOrientationproprietà in UIViewControllerclasse.
Sono disponibili 2 opzioni per rilevare l'orientamento dell'interfaccia:
Ciò che manca ancora è un modo per capire la direzione di un cambio di orientamento dell'interfaccia, che è molto importante durante le animazioni.
Nella sessione del WWDC 2014 "Visualizza avanzamento controller in iOS8" anche l'altoparlante fornisce una soluzione a quel problema, usando il metodo che sostituisce -will/DidRotateToInterfaceOrientation.
Qui la soluzione proposta è stata parzialmente implementata, maggiori informazioni qui :
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)
}
}
So che questa domanda è utile Swift, ma poiché è uno dei principali collegamenti per una ricerca su Google e se stai cercando lo stesso codice in 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
}
Semplice, funziona su iOS8 e 9 / Swift 2 / Xcode7, basta inserire questo codice nel tuo viewcontroller.swift. Stamperà le dimensioni dello schermo ad ogni cambio di orientamento, puoi invece inserire il tuo codice:
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()non funziona in modo affidabile. Manca alcune rotazioni. iewWillTransitionToSize:withTransitionCoordinator:funziona bene
Mi piace controllare la notifica di orientamento perché è possibile aggiungere questa funzione in qualsiasi classe, non è necessario essere una vista o un controller di vista. Anche nel delegato dell'app.
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)
della memorizzazione nella cache della notifica
@objc func orientationChanged(notification : NSNotification) {
//your code there
}
Nell'obiettivo C
-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
In fretta
func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
Sostituisci questo metodo per rilevare la modifica dell'orientamento.
Swift 3 | UIDeviceOrientationDidChange Notifica osservata troppo spesso
Il codice seguente stampa "deviceDidRotate" ogni volta che il dispositivo cambia orientamento nello spazio 3D, indipendentemente dal passaggio dall'orientamento verticale a quello orizzontale. Ad esempio, se si tiene il telefono in orientamento verticale e lo si inclina in avanti e indietro, viene chiamato ripetutamente deviceDidRotate ().
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(deviceDidRotate),
name: .UIDeviceOrientationDidChange,
object: nil
)
}
func deviceDidRotate() {
print("deviceDidRotate")
}
Per ovviare a questo problema, è possibile mantenere l'orientamento del dispositivo precedente e verificare la presenza di una modifica in 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")
}
In alternativa, puoi utilizzare una notifica diversa che viene chiamata solo quando il dispositivo passa da orizzontale a verticale. In questo caso, ti consigliamo di utilizzare la UIApplicationDidChangeStatusBarOrientationnotifica.
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(deviceDidRotate),
name: .UIApplicationDidChangeStatusBarOrientation,
object: nil
)
}
func deviceDidRotate() {
print("deviceDidRotate")
}
Implementazione completa e funzionante di come rilevare il cambiamento di orientamento in Swift 3.0.
Ho scelto di utilizzare questa implementazione, perché gli orientamenti del telefono di face upe face downsono stati importanti per me, e volevo la vista di cambiare solo una volta sapevo che l'orientamento era nella posizione specificata.
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")
}
}
}
I pezzi importanti da notare sono:
unknowna volte esiste un orientamento.Spero che qualcuno lo trovi utile.
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)")
}
Se vuoi fare qualcosa DOPO che la rotazione è completa, puoi usare il UIViewControllerTransitionCoordinatorgestore di completamento in questo modo
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()
}
}
Da iOS 8 questo è il modo corretto di farlo.
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`
})
}
Verifica se la rotazione è stata modificata con: viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
Con il coordinator.animateAlongsideTransition(nil) { (UIViewControllerTransitionCoordinatorContext) è possibile verificare se la transizione è terminata.
Vedi il codice qui sotto:
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")
}
}
Ecco un modo semplice per rilevare l'orientamento 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è deprecato ora, un uso migliore 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
}
}
Molte risposte non aiutano quando è necessario rilevare attraverso vari controller di visualizzazione. Questo fa il trucco.
viewWillDisappeare aggiungere addObserverin viewDidLoad. iOS annulla automaticamente la visualizzazione del controller.
UIDevice.current.orientation.isFlat
Il mio approccio è simile a quello che mostra bpedit sopra, ma con un focus iOS 9+. Volevo cambiare l'ambito di FSCalendar quando la vista ruota.
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)
}
Questo sotto ha funzionato, ma mi sono sentito imbarazzato :)
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
}
}
Uso UIUserInterfaceSizeClassper rilevare un orientamento modificato in una UIViewControllerclasse in questo modo:
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...
}
}
Per 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
Classe di installazione per ricevere notifiche sulla modifica dell'orientamento 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)
...
}
...
}
Codice gestore installazione:
@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: basta usare questo codice per identificare UIViewController in quale orientamento
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, l'orientamento restituisce sempre 0 fino alla rotazione del dispositivo. Devo chiamare UIDevice.current.beginGeneratingDeviceOrientationNotifications () per ottenere la rotazione effettiva prima che si verifichi qualsiasi evento di rotazione.