J'utilise Swift et je veux pouvoir charger un UIViewController lorsque je passe en mode paysage. Quelqu'un peut-il m'indiquer la bonne direction?
Je ne trouve rien en ligne et un peu dérouté par la documentation.
Voici comment je l'ai fait fonctionner:
Dans AppDelegate.Swift
dans la fonction didFinishLaunchingWithOptions
, je mets:
NotificationCenter.default.addObserver(self, selector: #selector(AppDelegate.rotated), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
puis à l'intérieur de 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!
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
if UIDevice.current.orientation.isLandscape {
print("Landscape")
} else {
print("Portrait")
}
}
Nécessité de détecter une rotation lors de l’utilisation de la caméra avec AVFoundation
, et constaté que les méthodes didRotate
(now deprecated) & willTransition
ne répondaient pas à 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 fermeture reste la même que celle de 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)
Concernant la déclaration de dépréciation, mon commentaire initial était trompeur, je voulais donc le mettre à jour. Comme indiqué, l'utilisation de l'inférence @objc
a été déconseillée, ce qui était nécessaire pour utiliser un #selector
. En utilisant plutôt une fermeture, cela peut être évité et vous disposez maintenant d'une solution qui devrait éviter un blocage en raison de l'appel d'un sélecteur non valide.
Swift 4.0 Avec Swift 4.0, Apple nous a encouragés à ne pas utiliser le #selector
; cette approche utilise donc maintenant un bloc d'achèvement. Cette approche est également rétro-compatible avec Swift 3.x et serait l'approche recommandée pour les années à venir.
Ceci est l'avertissement du compilateur que vous recevrez dans un projet Swift 4.x si vous utilisez la fonction #selector
en raison de la désapprobation de l'inférence @objc
:
Entrée dans Swift-é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 propriété -orientation
de UIDevice
n'est pas correcte (même si cela pourrait fonctionner dans la plupart des cas) et pourrait conduire à des bugs, par exemple UIDeviceOrientation
considère également l'orientation du périphérique s'il est face visible ou non, UIInterfaceOrientation
enum pour ces 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.
D'un autre côté, iOS8 a déconseillé d'utiliser la propriété interfaceOrientation
sur la classe UIViewController
.
Deux options sont 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 "Progression du contrôleur de visualisation dans iOS8", le haut-parleur fournit également une solution à ce problème, à l'aide de la méthode qui remplace -will/DidRotateToInterfaceOrientation
.
Ici la solution proposée partiellement mise en œuvre, 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)
}
}
Facile, cela fonctionne dans 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)
}
Je sais que cette question est pour Swift
, mais puisqu'il s'agit d'un des principaux 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
}
Utilisez le nouveau ViewWillTransitionToSize (_: withTransitionCoordinator :)
Swift 3 | Notification UIDeviceOrientationDidChange observée trop souvent
Le code suivant imprime "deviceDidRotate" chaque fois que votre périphérique change d'orientation dans l'espace 3D - indépendamment du passage de l'orientation portrait à l'orientation paysage. Par exemple, si vous tenez votre téléphone en orientation portrait et que vous l'inclinez en avant et en 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")
}
Vous pouvez également utiliser une notification différente qui n'est appelée que lorsque le périphérique passe de paysage à portrait. Dans ce cas, vous voudriez utiliser la notification UIApplicationDidChangeStatusBarOrientation
.
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(deviceDidRotate),
name: .UIApplicationDidChangeStatusBarOrientation,
object: nil
)
}
func deviceDidRotate() {
print("deviceDidRotate")
}
En objectif c
-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
En rapide
func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
Ignorez cette méthode pour détecter le changement d'orientation.
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)")
}
Mise en œuvre complète de la procédure de détection du changement d’orientation dans Swift 3.0.
J'ai choisi d'utiliser cette implémentation car les orientations téléphoniques face up
et face down
étaient importantes pour moi et je souhaitais que la vue ne change que lorsque 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 pièces importantes à noter sont:
unknown
.J'espère que quelqu'un trouve cela utile.
Voici un moyen simple de détecter l’orientation du périphérique: ( 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
}
}
Vérifiez si la rotation a été modifiée avec: viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
Avec 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")
}
}
J'aime vérifier la notification d'orientation car vous pouvez ajouter cette fonctionnalité à n'importe quelle classe. Il n'est pas nécessaire que ce soit une vue ou un contrôleur de vue. Même dans votre délégué de l'application.
//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 de mettre en cache la notification
func orientationChanged(notification : NSNotification) {
//your code there
}
Si vous voulez faire quelque chose APRÈS que la rotation soit terminée, vous pouvez utiliser le gestionnaire d'achèvement UIViewControllerTransitionCoordinator
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()
}
}
Pour Swift 3
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
if UIDevice.current.orientation.isLandscape {
//Landscape
}
else {
//Portrait
}
}
Mon approche est similaire à ce que bpedit montre ci-dessus, mais avec un focus iOS 9+. Je voulais changer le champ d'application de 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)
}
Ce ci-dessous a fonctionné, mais je me suis senti 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 classe UIViewController
comme ceci:
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...
}
}
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 ne permettent pas de détecter plusieurs contrôleurs de vue. Celui-ci fait le tour.
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`
})
}
- (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");
}
}
NOTE: Utilisez juste ce code pour identifier UIViewController dans quelle orientation