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.swift
all'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!
selector
avere un formato stringa di "rotated:"
??
rotated()
non lo fanno)
UIDeviceOrientation
è qualcosa di diverso da UIInterfaceOrientation
questo. Questo perché UIDeviceOrientation
rileva 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 AVFoundation
e ho scoperto che i metodi didRotate
( ora deprecati ) e willTransition
non 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 @objc
dell'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 #selector
funzione a causa della deprecazione @objc
dell'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 -orientation
proprietà di UIDevice
non è corretto (anche se potrebbe funzionare nella maggior parte dei casi) e potrebbe portare ad alcuni bug, ad esempio UIDeviceOrientation
prendere in considerazione anche l'orientamento del dispositivo se è rivolto verso l'alto o verso il basso, non esiste alcuna coppia diretta in UIInterfaceOrientation
enum 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 interfaceOrientation
proprietà in UIViewController
classe.
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 UIApplicationDidChangeStatusBarOrientation
notifica.
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 up
e face down
sono 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:
unknown
a 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 UIViewControllerTransitionCoordinator
gestore 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.
viewWillDisappear
e aggiungere addObserver
in 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 UIUserInterfaceSizeClass
per rilevare un orientamento modificato in una UIViewController
classe 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.