Come forzare un UIViewController all'orientamento verticale in iOS 6


85

Poiché ShouldAutorotateToInterfaceOrientationè deprecato in iOS 6 e l'ho usato per forzare una vista particolare solo in verticale , qual è il modo corretto per farlo in iOS 6? Questo è solo per un'area della mia app, tutte le altre visualizzazioni possono ruotare.

Risposte:


117

Se desideri che tutti i nostri controller di navigazione rispettino il controller della vista dall'alto, puoi utilizzare una categoria in modo da non dover passare attraverso e modificare un gruppo di nomi di classi.

@implementation UINavigationController (Rotation_IOS6)

-(BOOL)shouldAutorotate
{
    return [[self.viewControllers lastObject] shouldAutorotate];
}

-(NSUInteger)supportedInterfaceOrientations
{
    return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}

@end

Come indicano alcuni commenti, questa è una soluzione rapida al problema. Una soluzione migliore è la sottoclasse UINavigationController e inserire questi metodi lì. Una sottoclasse aiuta anche a supportare 6 e 7.


3
Posso confermare che funziona. Puoi anche sostituire "[self.viewControllers lastObject]" con "self.topViewController", se lo desideri.
Wayne Liu,

3
Se stai usando UITabBarController, questa categoria UINavigationController non è di aiuto. Dovresti invece creare una categoria su UITabBarController ...
Borut Tomazin

46
Il problema con questa soluzione è che non funziona quando apri il controller che era in orizzontale e il tuo nuovo controller superiore supporta solo il ritratto (o viceversa), quei callback non vengono chiamati in questo caso e devo ancora trovare il modo di farlo forzare l'orientamento corretto del nuovo controller superiore. Qualche idea?
Lope

4
Ho sottoclasse UINavigationController e l'ho impostato come window.rootController. Ho implementato tutti e 3 i metodi, funziona alla grande quando cambi la rotazione del dispositivo, il problema è che quei metodi (e nulla relativo alla rotazione) vengono chiamati quando apri il controller di visualizzazione
Lope

4
Se sto eseguendo push o pop dal controller della vista orizzontale, questa forza UIViewController cambia in Landscape. Tuttavia, se ruoto in verticale, funziona bene e non si trasformerà mai in orizzontale. L'unico problema durante il push o il pop dal paesaggio. Per favore aiuto
Tariq

63

Il modo migliore per iOS6 in particolare è indicato in "iOS6 By Tutorials" dal team di Ray Wenderlich - http://www.raywenderlich.com/ ed è migliore della sottoclasse UINavigationControllerper la maggior parte dei casi.

Sto usando iOS6 con uno storyboard che include un UINavigationControllerset come controller di visualizzazione iniziale.

//AppDelegate.m - purtroppo questo metodo non è disponibile prima di iOS6

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
NSUInteger orientations = UIInterfaceOrientationMaskAllButUpsideDown;

if(self.window.rootViewController){
    UIViewController *presentedViewController = [[(UINavigationController *)self.window.rootViewController viewControllers] lastObject];
    orientations = [presentedViewController supportedInterfaceOrientations];
}

return orientations;
}

//MyViewController.m - restituisce gli orientamenti che desideri supportare per ciascuno UIViewController

- (NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskPortrait;
}

1
Questa è la soluzione migliore per iOS 6
Homam

2
@Phil, funziona bene per iOS 6. Ma in alcuni casi, ad esempio se passi da orizzontale a verticale, non funziona. Qualche idea sul perché succede?
Kirti Nikam

1
Soluzione molto utile. Per me il migliore.
oscar castellon

1
Lavorando su iOS 7 beta 6. Nel mio caso, funziona quando si passa da orizzontale a verticale.
Martin Berger

Sono in iOS 6 ma non funziona. Si interrompe sulla riga "UIViewController * PresentViewController".
Marcel Marino

39

Questa risposta si riferisce alle domande poste nei commenti del post del PO:

Per forzare la visualizzazione di una vista in un determinato orientamento, visualizzare quanto segueWillAppear:

UIApplication* application = [UIApplication sharedApplication];
if (application.statusBarOrientation != UIInterfaceOrientationPortrait)
{
    UIViewController *c = [[UIViewController alloc]init];
    [self presentModalViewController:c animated:NO];
    [self dismissModalViewControllerAnimated:NO];
}

È un po 'un trucco, ma questo costringe UIViewControllera essere presentato in verticale anche se il controller precedente era orizzontale

AGGIORNAMENTO per iOS7

I metodi precedenti sono ora deprecati, quindi per iOS 7 utilizza quanto segue:

UIApplication* application = [UIApplication sharedApplication];
if (application.statusBarOrientation != UIInterfaceOrientationPortrait)
{
     UIViewController *c = [[UIViewController alloc]init];
     [c.view setBackgroundColor:[UIColor redColor]];
     [self.navigationController presentViewController:c animated:NO completion:^{
            [self.navigationController dismissViewControllerAnimated:YES completion:^{
            }];
     }];
}

È interessante notare che, al momento della scrittura, sia presente o respingere deve essere animata. In caso contrario, verrà visualizzata una schermata bianca. Non ho idea del perché questo lo faccia funzionare, ma funziona! L'effetto visivo è diverso a seconda di quale è animato.


Grazie, ci proverò quando troverò qualche minuto di tempo libero
Lope

@RohanAgarwal funziona come pubblicizzato, lo sto usando qui. Ma è necessario implementare anche il codice della risposta accettata, altrimenti non funzionerà.
Dennis Munsie

2
Qualcuno ha capito come farlo funzionare con l'animazione di rotazione corretta allo stesso tempo? È un po 'stridente vederlo passare da verticale a orizzontale senza l'animazione. Funziona, sperando solo di farlo funzionare un po 'meglio.
Dennis Munsie

@ Craig Watkinson Non funziona nello storyboard. e presentModalViewController e dismissModalViewControllerAnimated è deprecato se iam utilizza presentVirecontroller, allora non funzionerà. Per favore aiutami
Kalpesh

1
Per ios8 dismissViewControllerAnimated si blocca. Ho scoperto che chiamando [NWSAppDelegate sharedInstance] .window.rootViewController = nil; [NWSAppDelegate sharedInstance] .window.rootViewController = previousRootController funziona bene.
Alexey

36

Quindi ho riscontrato lo stesso problema durante la visualizzazione delle viste modali solo verticali. Normalmente, creerei un UINavigationController, lo imposterei viewControllercome rootViewController, quindi visualizzerei UINavigationControllercome una visualizzazione modale. Ma con iOS 6, viewControllerora chiederà al navigationController gli orientamenti dell'interfaccia supportati (che, per impostazione predefinita, ora è tutto per iPad e tutto tranne che capovolto per iPhone).

Soluzione : ho dovuto creare una sottoclasse UINavigationControllere sovrascrivere i metodi di autorotazione. Un po 'zoppo.

- (BOOL)shouldAutorotate {
    return NO;
}

- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}
// pre-iOS 6 support 
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    return (toInterfaceOrientation == UIInterfaceOrientationPortrait);
}

1
non funziona sul mio. Ho avuto questo codice con l'
impostazione

2
supportedInterfaceOrientations dovrebbe restituire un NSUInteger, non BOOL. Vedi developer.apple.com/library/ios/#featuredarticles/…
tomwhipple

ha funzionato, per me è il tabbarcontroller, ancora grazie per la risposta
otakuProgrammer

FWIW, anch'io ho dovuto seguire questa strada ... Nient'altro ha funzionato. Grazie.
Steve N

15

IOS 5

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{

    return (interfaceOrientation == UIInterfaceOrientationPortrait);

}

IOS 6

-(BOOL)shouldAutorotate{
    return YES;
}

-(NSInteger)supportedInterfaceOrientations{

    //    UIInterfaceOrientationMaskLandscape;
    //    24
    //
    //    UIInterfaceOrientationMaskLandscapeLeft;
    //    16
    //
    //    UIInterfaceOrientationMaskLandscapeRight;
    //    8
    //
    //    UIInterfaceOrientationMaskPortrait;
    //    2

    //    return UIInterfaceOrientationMaskPortrait; 
    //    or
          return 2;
}

Eccellente! Devi essere al massimo in cima a questo thread. Perché è il modo più semplice per risolvere il problema
Alex

@Roshan Jalgaonkar In ios 6 Non funziona per me, ho bisogno solo del ritratto con il pulsante Home in basso come posso impostare questo orientamento UIO ....
Karthik

@Karthik devi abilitare le rotazioni supportate nel target della tua app affinché funzioni.
Alejandro Iván

@ AlejandroIván k thnx
Karthik

10

Non sono d'accordo con la risposta di @aprato, perché i metodi di rotazione di UIViewController sono dichiarati nelle categorie stesse, determinando così un comportamento indefinito se si sovrascrive in un'altra categoria. È più sicuro sovrascriverli in una sottoclasse UINavigationController (o UITabBarController)

Inoltre, questo non copre lo scenario in cui si spinge / presenta / si apre da una vista orizzontale a una VC solo verticale o viceversa. Per risolvere questo difficile problema (mai risolto da Apple), dovresti:

In iOS <= 4 e iOS> = 6:

UIViewController *vc = [[UIViewController alloc]init];
[self presentModalViewController:vc animated:NO];
[self dismissModalViewControllerAnimated:NO];
[vc release];

In iOS 5:

UIWindow *window = [[UIApplication sharedApplication] keyWindow];
UIView *view = [window.subviews objectAtIndex:0];
[view removeFromSuperview];
[window addSubview:view];

Questi costringeranno VERAMENTE UIKit a rivalutare tutti i tuoi dovrebberoAutorotate, SupportInterfaceOrientations, ecc.


2
Il primo di questi arresti anomali per me indipendentemente dalla versione iOS. Dice che il licenziamento non dovrebbe essere chiamato prima che il presente sia finito.
arsenius

@arsenius Puoi pubblicare uno snippet di come lo stai usando? Finché non è animato non dovrebbe avere il problema che hai menzionato
Rafael Nobre

Ho anche messo il secondo frammento di in viewDidAppear e non fa nulla per aiutare la mia situazione su iOS 6. La domanda è qui: stackoverflow.com/questions/15654339/...
Arsenio

Scusa, un ultimo commento qui. Lo spostamento del codice iOS 5 in viewDidAppear crea una sorta di ciclo infinito con questo output: - Overflow di [UIApplication beginIgnoringInteractionEvents]. Ignorando.
arsenius

3

Ho un ottimo approccio mescolando https://stackoverflow.com/a/13982508/2516436 e https://stackoverflow.com/a/17578272/2516436

-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
    NSUInteger orientations = UIInterfaceOrientationMaskAllButUpsideDown;


    if(self.window.rootViewController){
        UIViewController *presentedViewController = [self topViewControllerWithRootViewController:self.window.rootViewController];
        orientations = [presentedViewController supportedInterfaceOrientations];
    }

    return orientations;
}

- (UIViewController*)topViewControllerWithRootViewController:(UIViewController*)rootViewController {
    if ([rootViewController isKindOfClass:[UITabBarController class]]) {
        UITabBarController* tabBarController = (UITabBarController*)rootViewController;
        return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
    } else if ([rootViewController isKindOfClass:[UINavigationController class]]) {
        UINavigationController* navigationController = (UINavigationController*)rootViewController;
        return [self topViewControllerWithRootViewController:navigationController.visibleViewController];
    } else if (rootViewController.presentedViewController) {
        UIViewController* presentedViewController = rootViewController.presentedViewController;
        return [self topViewControllerWithRootViewController:presentedViewController];
    } else {
        return rootViewController;
    }
}

e restituisci gli orientamenti che desideri supportare per ogni UIViewController

- (NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskPortrait;
}

1

Ho un'app universale relativamente complessa che utilizza UISplitViewController e UISegmentedController e ho alcune visualizzazioni che devono essere presentate in Landscape utilizzando presentViewController . Utilizzando i metodi suggeriti sopra, sono riuscito a far funzionare in modo accettabile iPhone ios 5 e 6, ma per qualche motivo l'iPad si è semplicemente rifiutato di presentarsi come Landscape. Infine, ho trovato una soluzione semplice (implementata dopo ore di lettura e tentativi ed errori) che funziona sia per i dispositivi che per ios 5 e 6.

Passaggio 1) Sul controller, specificare l'orientamento richiesto (più o meno come indicato sopra)

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}

-(BOOL)shouldAutorotate
{
    return YES;
}

-(NSUInteger)supportedInterfaceOrientations
{
    NSInteger mask = UIInterfaceOrientationMaskLandscape;
    return mask;

}

Passaggio 2) Creare una semplice sottoclasse UINavigationController e implementare i seguenti metodi

-(BOOL)shouldAutorotate {
        return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
        return UIInterfaceOrientationMaskLandscape;
}

Passaggio 3) Presenta il tuo viewController

vc = [[MyViewController alloc]init];
MyLandscapeNavigationController *myNavigationController = [[MyLandscapeNavigationController alloc] initWithRootViewController:vc];
[self myNavigationController animated:YES completion:nil];

Spero che questo sia utile a qualcuno.


1

Non essere noioso qui, ma saresti così gentile da condividere la tua sottoclasse? Grazie.

modifica: beh, finalmente l'ho fatto, la sottoclasse era semplicissima da fare. Dovevo solo dichiarare navigationControllerin AppDelegateas UINavigationControllerSubclassinvece del valore predefinito UINavigationController, quindi ho modificato la tua sottoclasse con:

- (BOOL)shouldAutorotate {
    return _shouldRotate;
}

così posso impostare qualsiasi vista che voglio ruotare o meno chiamando a viewDidLoad

_navController = (UINavigationController *)self.navigationController;
[_navController setShouldRotate : YES / NO]

Spero che questo tweak possa aiutare anche gli altri, grazie per il tuo suggerimento!

Suggerimento: fai uso di

- (NSUInteger)supportedInterfaceOrientations

nei controller di visualizzazione, in modo da non avere una vista desiderata in verticale in orizzontale o viceversa.


0

Non l'ho testato da solo, ma la documentazione afferma che ora è possibile sovrascrivere questi metodi: supportedInterfaceOrientationse preferredInterfaceOrientationForPresentation.

Probabilmente puoi ottenere ciò che desideri impostando solo l'orientamento che desideri in quei metodi.


0

Le risposte che utilizzano sottoclassi o categorie per consentire i VC all'interno delle classi UINavigationController e UITabBarController funzionano bene. L'avvio di una modalità solo verticale da un controller della barra delle schede orizzontale non è riuscito. Se è necessario eseguire questa operazione, utilizzare il trucco di visualizzare e nascondere una visualizzazione modale non animata, ma farlo nel metodo viewDidAppear . Non ha funzionato per me in viewDidLoad o viewWillAppear.

A parte questo, le soluzioni di cui sopra funzionano bene.


0

Per Monotouch puoi farlo in questo modo:

public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations()
    {
    return UIInterfaceOrientationMask.LandscapeRight;
}

public override UIInterfaceOrientation PreferredInterfaceOrientationForPresentation()
    {
    return UIInterfaceOrientation.LandscapeRight;
}


-1

Basta andare su project.plist quindi aggiungere Orientamento dell'interfaccia supportato e quindi aggiungere solo Ritratto (pulsante home in basso) e Ritratto (pulsante home in alto).

È possibile aggiungere o rimuovere l'orientamento in base ai requisiti del progetto.

Grazie


1
si tratta di un particolare controller di visualizzazione non per l'intera applicazione.
Muhammad Rizwan

-2

1) Controlla le impostazioni del tuo progetto e info.plist e assicurati che siano selezionati solo gli orientamenti che desideri.

2) aggiungi i seguenti metodi al controller di visualizzazione più in alto (controller di navigazione / controller della barra delle schede)

- (NSUInteger) supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;

}

3) aggiungi i seguenti metodi al tuo delegato dell'app

- (NSUInteger) supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;

}

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
    return UIInterfaceOrientationMaskPortrait;

}

-3

Mettilo nel file .m di ogni file ViewControllerche non vuoi ruotare:

- (NSUInteger)supportedInterfaceOrientations
{
    //return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft;
    return UIInterfaceOrientationMaskPortrait;
}

Vedi qui per maggiori informazioni.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.