Domanda

Ho una gerarchia di visualizzazione nidificata per un'applicazione iPad che supporta le modifiche all'orientamento. Sembra simile a quanto segue.

UIViewController
    UIView
        - UIView
            - UIImageView (disable rotation)
            - UIImageView
            - UIView (disable rotation)
        - UIView
        - UIView
        ...

Vorrei bloccare l'orientamento per alcune delle mie sotto-viste, consentendo agli altri di essere auto-rotonti e ridimensionarsi. Non riesco proprio a capire come raggiungere questo obiettivo.

Un approccio sembra ruotare manualmente le sottoviste all'interno willAnimateRotationToInterfaceOrientation:. Questo non è particolarmente attraente, dato che l'SDK sta eseguendo una rotazione che vorrei solo annullare.

C'è un modo per disabilitare semplicemente le modifiche all'orientamento per le sottoviste o qualche altro metodo per ristrutturare la mia gerarchia?

È stato utile?

Soluzione

L'autorotazione è gestita da UiviewController di una vista (shouldAutorotateToInterfaceOrientation:), quindi un approccio è quello di organizzare la tua gerarchia in modo tale che le viste rotabili siano gestite da un controller di visualizzazione e viste non rotabili da un altro controller di visualizzazione. Entrambe queste visualizzazioni di root di UiviewController hanno quindi bisogno di aggiungere alla finestra/Superiew.

La sottigliezza qui è che se hai due viste del controller di visualizzazione allo stesso livello (cioè aggiunte tramite addSubview:), solo il primo controller di visualizzazione (di solito la finestra rootViewController) riceverà il shouldAutorotateToInterfaceOrientation: Messaggio.

Ho usato questo approccio per ottenere una barra degli strumenti che ruota, mentre la vista principale no.

QA1688 di Apple QA1688 ("Perché il mio UiviewController non ruota con il dispositivo?") Parla un po 'di questo problema.


Aggiornamento per iOS 6:

L'autorotazione ora usa UIViewController'S shouldAutorotate e supportedInterfaceOrientations metodi. shouldAutorotate ritorna YES Per impostazione predefinita, ma ricorda che un controller di visualizzazione diverso dal rootViewController La cui vista è una sub -view diretta della finestra non riceverà comunque callback di rotazione.


Codice di esempio per iOS 6:

Crea un nuovo progetto utilizzando il modello "Applicazione singola Visualizza" e assicurati che "Usa gli storyboard" venga selezionato. Useremo il fornito ViewController classe come controller di visualizzazione rotante (rinomina se vuoi!) E crea un secondo UIViewController sottoclasse chiamato NonRotatingViewController. Sebbene questo controller di visualizzazione non riceva mai nemmeno i callback di rotazione, per completezza e chiarezza aggiungi il seguente codice in NonRotatingViewController.m:

- (BOOL)shouldAutorotate
{
    return NO;
}

Nel MainStoryboard file, trascina un nuovo oggetto controller di visualizzazione e imposta la sua classe su NonRotatingViewController, e impostare il suo ID storyboard su "non rotatingvc". Mentre sei lì, modifica il colore di sfondo del controller della vista rotante in eliminazione (la vista non rotante verrà aggiunta sotto questa) e aggiungi un'etichetta a ciascuna vista. In AppDelegate.m, Aggiungi il seguente codice:

#import "NonRotatingViewController.h"

// ...
// ...

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
    UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
    NonRotatingViewController *nonRotatingVC = [mainStoryboard instantiateViewControllerWithIdentifier:@"NonRotatingVC"];
    [self.window addSubview:nonRotatingVC.view];
    return YES;
}

Questo è solo istanziare un controller di vista non rotante e aggiungere la sua vista direttamente alla finestra (NB a questo punto la finestra rootViewController è già stato impostato dallo storyboard).

Esegui il progetto. Ruota il dispositivo e meravigliarsi alla vista di un'etichetta che ruota mentre l'altra rimane immobile!


Codice di esempio pre iOS 6:

L'ho fatto in un nuovo progetto: una nuova applicazione basata sulla vista andrà bene. Aggiungi due nuovi controller di visualizzazione: RotatingViewController e NonRotatingViewController. All'interno di ciascuno dei loro pennini ho appena aggiunto un'etichetta per descrivere se la vista dovrebbe ruotare o meno. Aggiungi il seguente codice:

'RotatingViewController.m'

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


'NonRotatingViewController.m'

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    if (interfaceOrientation == UIInterfaceOrientationPortrait) {    // Or whatever orientation it will be presented in.
        return YES;
    }
    return NO;
}


'AppDelegate.m'

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    RotatingViewController *rotating = [[RotatingViewController alloc] initWithNibName:@"RotatingViewController" bundle:nil];
    self.rotatingViewController = rotating;
    [rotating release];

    NonRotatingViewController *nonRotating = [[NonRotatingViewController alloc] initWithNibName:@"NonRotatingViewController" bundle:nil];
    self.nonRotatingViewController = nonRotating;
    [nonRotating release];

    [self.window addSubview:self.rotatingViewController.view];
    [self.window insertSubview:self.nonRotatingViewController.view belowSubview:self.rotatingViewController.view];

    [self.window makeKeyAndVisible];

    return YES;
}

Spero che questo aiuti.

Altri suggerimenti

Ecco un altro modo. Basta inserire questo codice nel tuo ViewController ViewDidload:

    YourAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
        // the view you don't want rotated (there could be a heierarchy of views here):
    UIView *nonRotatingView = [[UIView alloc] initWithFrame:CGRectMake(100,0,30,500)];
    nonRotatingView.backgroundColor = [UIColor purpleColor];

        // make sure self.view and its children are transparent so you can see through to this view that will not be rotated behind self.view.

    [delegate.window insertSubview:nonRotatingView  belowSubview:self.view];

        // you can't put it in the front using:
        //    [delegate.window insertSubview:nonRotatingView aboveSubview:self.view];
        // It will show up the same as before

    // you should declare nonRotatingView as a property so you can easily access it for removal, etc.

Il mio approccio alla risoluzione di questo problema è fare una contromisura usando UINotification Per rilevare la rotazione automatica e ruotare la vista al contrario.

Trova il codice completo qui:
https://gist.github.com/ffraenz/5945301

- (void)orientationDidChangeNotificationReceived:(NSNotification *)notification
{
    // find out needed compass rotation
    //  (as a countermeasure to auto rotation)
    float rotation = 0.0;

    if (self.interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
        rotation = M_PI;
    else if (self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft)
        rotation = M_PI / 2.0;
    else if (self.interfaceOrientation == UIInterfaceOrientationLandscapeRight)
        rotation = M_PI / (- 2.0);

    // rotate compass without auto rotation animation
    //  iOS rotation animation duration is 0.3
    //  this excludes the compassView from the auto rotation
    //  (same effect as in the camera app where controls do rotate and camera viewport don't)
    [UIView animateWithDuration:0.3 animations:^(void) {
        self.compassView.transform = CGAffineTransformMakeRotation(rotation);
    }];
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top