Estou usando o Swift e quero poder carregar um UIViewController quando eu rodar para paisagem, alguém pode me apontar na direção certa?
Não consigo encontrar nada online e um pouco confuso com a documentação.
Estou usando o Swift e quero poder carregar um UIViewController quando eu rodar para paisagem, alguém pode me apontar na direção certa?
Não consigo encontrar nada online e um pouco confuso com a documentação.
Respostas:
Aqui está como eu consegui:
No AppDelegate.swift
interior da didFinishLaunchingWithOptions
função Coloquei:
NotificationCenter.default.addObserver(self, selector: #selector(AppDelegate.rotated), name: UIDevice.orientationDidChangeNotification, object: nil)
e depois dentro da classe AppDelegate, coloquei a seguinte função:
func rotated() {
if UIDeviceOrientationIsLandscape(UIDevice.current.orientation) {
print("Landscape")
}
if UIDeviceOrientationIsPortrait(UIDevice.current.orientation) {
print("Portrait")
}
}
Espero que isso ajude mais alguém!
Obrigado!
selector
ter um formato de string de "rotated:"
??
rotated()
não)
UIDeviceOrientation
é algo diferente de UIInterfaceOrientation
.. Isso ocorre porque UIDeviceOrientation
também detecta orientações voltadas para baixo e para cima, o que significa que seu código pode pular entre retrato e paisagem aleatoriamente se o dispositivo estiver apoiado em uma superfície quase plana, mas levemente irregular (ou seja, balançando na saliência). camera of the 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")
}
}
Preciso detectar a rotação ao usar a câmera AVFoundation
e constatou que os métodos didRotate
( agora obsoletos ) e willTransition
não eram confiáveis para minhas necessidades. O uso da notificação postada por David funcionou, mas não é atual para o Swift 3.x / 4.x.
Swift 4.2 O nome da notificação foi alterado.
O valor do fechamento permanece o mesmo do 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")
}
}
Para configurar a notificação para o Swift 4.2 :
NotificationCenter.default.addObserver(forName: UIDevice.orientationDidChangeNotification,
object: nil,
queue: .main,
using: didRotate)
Para remover a notificação do Swift 4.2 :
NotificationCenter.default.removeObserver(self,
name: UIDevice.orientationDidChangeNotification,
object: nil)
Em relação à declaração de reprovação , meu comentário inicial foi enganoso, então eu queria atualizá-la. Como observado, o uso de @objc
inferência foi descontinuado, o que, por sua vez, era necessário para usar a #selector
. Ao usar um fechamento, isso pode ser evitado e agora você tem uma solução que deve evitar uma falha devido à chamada de um seletor inválido.
Swift 4.0
Com o Swift 4.0, a Apple nos incentivou a evitar o uso #selector
, portanto essa abordagem usa um bloco de conclusão agora. Essa abordagem também é compatível com o Swift 3.x e seria a abordagem recomendada daqui para frente.
Este é o aviso do compilador que você receberá em um projeto Swift 4.x se você usar a #selector
função devido à descontinuação da @objc
inferência:
Entrada em rápida evolução sobre essa mudança .
Configure o retorno de chamada:
// 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")
}
}
Configure a notificação:
NotificationCenter.default.addObserver(forName: .UIDeviceOrientationDidChange,
object: nil,
queue: .main,
using: didRotate)
Rasgue-o:
NotificationCenter.default.removeObserver(self, name: .UIDeviceOrientationDidChange, object: nil)
Usando -orientation
propriedade de UIDevice
não está correto (mesmo que possa funcionar na maioria dos casos) e pode levar a alguns erros, por exemplo, UIDeviceOrientation
considere também a orientação do dispositivo se estiver com a face para cima ou para baixo, não há par direto na UIInterfaceOrientation
enumeração para aqueles valores.
Além disso, se você bloquear seu aplicativo em alguma orientação específica, o UIDevice fornecerá a orientação do dispositivo sem levar isso em conta.
Por outro lado, o iOS8 substituiu a interfaceOrientation
propriedade na UIViewController
classe.
Existem 2 opções disponíveis para detectar a orientação da interface:
O que falta ainda é uma maneira de entender a direção de uma mudança na orientação da interface, que é muito importante durante as animações.
Na sessão da WWDC 2014 "Ver avanço do controlador no iOS8", o alto-falante também fornece uma solução para esse problema, usando o método que substitui -will/DidRotateToInterfaceOrientation
.
Aqui a solução proposta foi parcialmente implementada, mais informações aqui :
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)
}
}
Sei que essa pergunta é válida Swift
, mas como é um dos principais links para uma pesquisa no Google e se você estiver procurando o mesmo código em 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
}
Fácil, isso funciona no iOS8 e 9 / Swift 2 / Xcode7, basta colocar esse código dentro do seu viewcontroller.swift. Ele imprimirá as dimensões da tela a cada mudança de orientação; você pode colocar seu próprio código:
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()
não funciona de maneira confiável. Falta algumas rotações. iewWillTransitionToSize:withTransitionCoordinator:
funciona ok.
Gosto de verificar a notificação de orientação, porque você pode adicionar esse recurso a qualquer classe, não precisa ser uma visão ou um controlador de visão. Mesmo no seu delegado do aplicativo.
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)
do que armazenar em cache a notificação
@objc func orientationChanged(notification : NSNotification) {
//your code there
}
No objetivo C
-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
Em rápido
func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
Substitua esse método para detectar a mudança de orientação.
Swift 3 | Notificação UIDeviceOrientationDidChange observada com muita frequência
O código a seguir imprime "deviceDidRotate" toda vez que seu dispositivo altera a orientação no espaço 3D - independentemente de uma alteração da orientação retrato para paisagem. Por exemplo, se você segurar o telefone na orientação retrato e inclinar para frente e para trás - o deviceDidRotate () será chamado repetidamente.
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(deviceDidRotate),
name: .UIDeviceOrientationDidChange,
object: nil
)
}
func deviceDidRotate() {
print("deviceDidRotate")
}
Para contornar isso, você pode manter a orientação anterior do dispositivo e verificar se há uma alteração no 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 você pode usar uma notificação diferente, que só é chamada quando o dispositivo muda de paisagem para retrato. Nesse caso, você deseja usar a UIApplicationDidChangeStatusBarOrientation
notificação.
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(deviceDidRotate),
name: .UIApplicationDidChangeStatusBarOrientation,
object: nil
)
}
func deviceDidRotate() {
print("deviceDidRotate")
}
Implementação completa de como detectar alterações de orientação no Swift 3.0.
Eu escolhi usar esta implementação, porque as orientações de telefone de face up
e face down
foram importantes para mim, e eu queria que o fim de alterar apenas uma vez eu sabia que a orientação estava na posição especificada.
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")
}
}
}
As peças importantes a serem observadas são:
unknown
orientações algumas vezes.Espero que alguém ache isso útil.
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 você quiser fazer algo APÓS a rotação estar concluída, use o UIViewControllerTransitionCoordinator
manipulador de conclusão como este
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()
}
}
Desde o iOS 8, essa é a maneira correta de fazer isso.
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`
})
}
Verifique se a rotação mudou com: viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
Com o coordinator.animateAlongsideTransition(nil) { (UIViewControllerTransitionCoordinatorContext)
você pode verificar se a transição está concluída.
Veja o código abaixo:
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")
}
}
Aqui está uma maneira fácil de detectar a orientação do 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
está obsoleto agora, melhor uso 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
}
}
Muitas respostas não ajudam quando é necessário detectar vários controladores de exibição. Este faz o truque.
viewWillDisappear
e adicionar addObserver
em viewDidLoad
. O cancelamento da inscrição no iOS exibe o controlador automaticamente.
UIDevice.current.orientation.isFlat
Minha abordagem é semelhante ao que o bpedit mostra acima, mas com um foco no iOS 9+. Eu queria alterar o escopo do FSCalendar quando a exibição gira.
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)
}
Isso abaixo funcionou, mas eu me senti envergonhado com isso :)
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
}
}
Eu uso UIUserInterfaceSizeClass
para detectar uma orientação alterada em uma UIViewController
classe assim:
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...
}
}
Para 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 configuração para receber notificações de alterações na orientação do 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)
...
}
...
}
Código do manipulador de instalação:
@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: Apenas use este código para identificar o UIViewController em qual orientação
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...
}
No iOS 13.1.2, a orientação sempre retorna 0 até que o dispositivo seja girado. Preciso chamar UIDevice.current.beginGeneratingDeviceOrientationNotifications () para obter a rotação real antes que ocorra qualquer evento de rotação.