J'utilise Swift et je souhaite pouvoir charger un UIViewController lorsque je tourne en mode paysage, est-ce que quelqu'un peut me diriger dans la bonne direction?
Je ne trouve rien en ligne et un peu confus par la documentation.
J'utilise Swift et je souhaite pouvoir charger un UIViewController lorsque je tourne en mode paysage, est-ce que quelqu'un peut me diriger dans la bonne direction?
Je ne trouve rien en ligne et un peu confus par la documentation.
Réponses:
Voici comment je l'ai fait fonctionner:
À l' AppDelegate.swift
intérieur de la didFinishLaunchingWithOptions
fonction, je mets:
NotificationCenter.default.addObserver(self, selector: #selector(AppDelegate.rotated), name: UIDevice.orientationDidChangeNotification, object: nil)
puis dans la classe AppDelegate, j'ai mis la fonction suivante:
func rotated() {
if UIDeviceOrientationIsLandscape(UIDevice.current.orientation) {
print("Landscape")
}
if UIDeviceOrientationIsPortrait(UIDevice.current.orientation) {
print("Portrait")
}
}
J'espère que cela aide quelqu'un d'autre!
Merci!
selector
avoir un format de chaîne de "rotated:"
??
rotated()
ne le fait pas)
UIDeviceOrientation
s'agit de quelque chose de différent de UIInterfaceOrientation
.. Ceci est dû au fait que UIDeviceOrientation
détecte également les orientations face vers le bas et face vers le haut, ce qui signifie que votre code peut basculer entre portrait et paysage de manière aléatoire si votre appareil repose sur une surface presque plate mais légèrement inégale (c.-à-d. Se balançant sur la saillie caméra des
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")
}
}
Besoin de détecter la rotation lors de l'utilisation de la caméra avec AVFoundation
, et j'ai constaté que les méthodes didRotate
( désormais obsolètes ) et willTransition
n'étaient pas fiables pour mes besoins. L'utilisation de la notification publiée par David a fonctionné, mais n'est pas à jour pour Swift 3.x / 4.x.
Swift 4.2 Le nom de la notification a été modifié.
La valeur de clôture reste la même 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")
}
}
Pour configurer la notification pour Swift 4.2 :
NotificationCenter.default.addObserver(forName: UIDevice.orientationDidChangeNotification,
object: nil,
queue: .main,
using: didRotate)
Pour supprimer la notification pour Swift 4.2 :
NotificationCenter.default.removeObserver(self,
name: UIDevice.orientationDidChangeNotification,
object: nil)
En ce qui concerne la déclaration d'obsolescence , mon commentaire initial était trompeur, je voulais donc le mettre à jour. Comme indiqué, l'utilisation de l' @objc
inférence a été déconseillée, ce qui était à son tour nécessaire pour utiliser un fichier #selector
. En utilisant une fermeture à la place, cela peut être évité et vous avez maintenant une solution qui devrait éviter un crash dû à l'appel d'un sélecteur invalide.
Swift 4.0
Avec Swift 4.0, Apple nous a encouragés à éviter d'utiliser le #selector
, donc cette approche utilise maintenant un bloc de complétion. Cette approche est également rétrocompatible avec Swift 3.x et serait l'approche recommandée à l'avenir.
Voici l'avertissement du compilateur que vous recevrez dans un projet Swift 4.x si vous utilisez la #selector
fonction en raison de la dépréciation de l' @objc
inférence:
Entrée en rapide évolution sur ce changement .
Configurez le rappel:
// 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")
}
}
Configurez la notification:
NotificationCenter.default.addObserver(forName: .UIDeviceOrientationDidChange,
object: nil,
queue: .main,
using: didRotate)
Détruit-le:
NotificationCenter.default.removeObserver(self, name: .UIDeviceOrientationDidChange, object: nil)
L'utilisation de la -orientation
propriété de UIDevice
n'est pas correcte (même si cela pourrait fonctionner dans la plupart des cas) et pourrait conduire à des bogues, par exemple, UIDeviceOrientation
considérez également l'orientation de l'appareil s'il est face vers le haut ou vers le bas, il n'y a pas de paire directe dans UIInterfaceOrientation
enum pour ceux valeurs.
De plus, si vous verrouillez votre application dans une orientation particulière, UIDevice vous donnera l'orientation de l'appareil sans en tenir compte.
De l'autre côté, iOS8 a désapprouvé la interfaceOrientation
propriété sur la UIViewController
classe.
Il existe 2 options disponibles pour détecter l'orientation de l'interface:
Ce qui manque encore, c'est un moyen de comprendre le sens d'un changement d'orientation de l'interface, ce qui est très important lors des animations.
Dans la session de WWDC 2014 «Afficher l'avancement du contrôleur dans iOS8», le haut-parleur fournit également une solution à ce problème, en utilisant la méthode qui remplace -will/DidRotateToInterfaceOrientation
.
Voici la solution proposée partiellement implémentée, plus d'infos ici :
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)
}
}
Je sais que cette question est pour Swift
, mais comme c'est l'un des meilleurs liens pour une recherche Google et si vous recherchez le même code dans 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
}
Facile, cela fonctionne sous iOS8 et 9 / Swift 2 / Xcode7, il suffit de mettre ce code dans votre viewcontroller.swift. Il imprimera les dimensions de l'écran à chaque changement d'orientation, vous pouvez mettre votre propre code à la place:
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()
ne fonctionne pas de manière fiable. Il manque quelques rotations. iewWillTransitionToSize:withTransitionCoordinator:
fonctionne bien.
Utilisez le nouveau viewWillTransitionToSize (_: withTransitionCoordinator :)
J'aime vérifier la notification d'orientation car vous pouvez ajouter cette fonctionnalité dans n'importe quelle classe, pas besoin d'être une vue ou un contrôleur de vue. Même dans votre délégué d'application.
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 la mise en cache de la notification
@objc func orientationChanged(notification : NSNotification) {
//your code there
}
Dans l'objectif C
-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
En rapide
func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
Remplacez cette méthode pour détecter le changement d'orientation.
Swift 3 | Notification UIDeviceOrientationDidChange observée trop souvent
Le code suivant imprime «deviceDidRotate» chaque fois que votre appareil change d'orientation dans l'espace 3D - indépendamment d'un changement de l'orientation portrait à l'orientation paysage. Par exemple, si vous tenez votre téléphone en orientation portrait et que vous l'inclinez vers l'avant et l'arrière, deviceDidRotate () est appelé à plusieurs reprises.
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(deviceDidRotate),
name: .UIDeviceOrientationDidChange,
object: nil
)
}
func deviceDidRotate() {
print("deviceDidRotate")
}
Pour contourner ce problème, vous pouvez conserver l'orientation précédente du périphérique et rechercher une modification dans 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")
}
Ou vous pouvez utiliser une notification différente qui n'est appelée que lorsque l'appareil passe du paysage au portrait. Dans ce cas, vous souhaitez utiliser la UIApplicationDidChangeStatusBarOrientation
notification.
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(deviceDidRotate),
name: .UIApplicationDidChangeStatusBarOrientation,
object: nil
)
}
func deviceDidRotate() {
print("deviceDidRotate")
}
Implémentation complète de la détection des changements d'orientation dans Swift 3.0.
J'ai choisi d'utiliser cette implémentation parce que les orientations du téléphone face up
et face down
étaient importantes pour moi, et je voulais que la vue ne change qu'une fois que je savais que l'orientation était dans la position spécifiée.
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")
}
}
}
Les éléments importants à noter sont:
unknown
parfois une orientation.J'espère que quelqu'un trouvera cela 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)")
}
Si vous voulez faire quelque chose APRÈS la rotation est terminée, vous pouvez utiliser le UIViewControllerTransitionCoordinator
gestionnaire de complétion comme ceci
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()
}
}
Depuis iOS 8, c'est la bonne façon de le faire.
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`
})
}
Vérifiez si la rotation a changé avec: viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
Avec le, coordinator.animateAlongsideTransition(nil) { (UIViewControllerTransitionCoordinatorContext)
vous pouvez vérifier si la transition est terminée.
Voir le code ci-dessous:
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")
}
}
Voici un moyen simple de détecter l'orientation de l'appareil: ( 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
est obsolète maintenant, meilleure utilisation 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
}
}
Beaucoup de réponses n'aident pas lorsque vous devez détecter sur différents contrôleurs de vue. Celui-ci fait l'affaire.
viewWillDisappear
et ajouter addObserver
à viewDidLoad
. iOS désabonne automatiquement le contrôleur de vue.
UIDevice.current.orientation.isFlat
Mon approche est similaire à ce que bpedit montre ci-dessus, mais avec un focus iOS 9+. Je voulais changer la portée du FSCalendar lorsque la vue pivote.
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)
}
Ceci ci-dessous a fonctionné, mais je me sentais penaud à ce sujet :)
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
}
}
J'utilise UIUserInterfaceSizeClass
pour détecter une orientation modifiée dans une UIViewController
classe comme ça:
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...
}
}
Pour 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 de configuration pour recevoir des notifications de changement d'orientation de l'appareil:
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)
...
}
...
}
Code du gestionnaire d'installation:
@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");
}
}
REMARQUE: utilisez simplement ce code pour identifier UIViewController dans quelle orientation
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...
}
Avec iOS 13.1.2, l'orientation renvoie toujours 0 jusqu'à ce que l'appareil pivote. Je dois appeler UIDevice.current.beginGeneratingDeviceOrientationNotifications () pour obtenir une rotation réelle avant tout événement de rotation.