it-swarm.dev

Gibt es eine dokumentierte Möglichkeit, die iPhone-Ausrichtung festzulegen?

Ich habe eine App, bei der ich die Gerätedrehung in bestimmten Ansichten unterstützen möchte, andere sind jedoch im Landschaftsmodus nicht besonders sinnvoll. Wenn Sie also die Ansichten austauschen, möchte ich, dass die Drehung auf Hochformat gesetzt wird.

Es gibt einen undokumentierten Eigenschaftssetter für UIDevice, der den Trick ausführt, aber offensichtlich eine Compiler-Warnung generiert und bei einer zukünftigen Revision des SDK verschwinden könnte.

[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait];

Gibt es dokumentierte Möglichkeiten, die Orientierung zu erzwingen?

Update: Ich dachte ich würde ein Beispiel geben, da ich nicht nach doAutorotateToInterfaceOrientation suche, da ich das bereits implementiert habe.

Ich möchte, dass meine App Querformat und Hochformat in Ansicht 1 unterstützt, jedoch nur Hochformat in Ansicht 2. Ich habe bereits für alle Ansichten "sollteAutorotateToInterfaceOrientation" implementiert. Wenn sich der Benutzer jedoch in Querformat 1 in Ansicht 1 befindet und dann zu Ansicht 2 wechselt, möchte ich die Telefon, um zum Porträt zurückzukehren.

94
Dave Verwer

Dies ist kein Problem mehr mit dem späteren iPhone 3.1.2 SDK. Es scheint nun die geforderte Ausrichtung der Ansicht zu berücksichtigen, die auf den Stapel zurückgeschoben wird. Dies bedeutet wahrscheinlich, dass Sie ältere Versionen des iPhone-Betriebssystems erkennen und die setOrientation nur anwenden müssen, wenn sie vor der neuesten Version liegt.

Es ist nicht klar, ob die statische Analyse von Apple versteht, dass Sie mit den älteren SDK-Einschränkungen umgehen. Ich persönlich wurde von Apple aufgefordert, den Methodenaufruf bei meinem nächsten Update zu entfernen. Ich bin mir noch nicht sicher, ob ein Hack für ältere Geräte den Genehmigungsprozess durchlaufen wird.

6
John K

Dies ist lange nach der Tatsache, aber nur für den Fall, dass jemand mitkommt, der keinen Navigationscontroller verwendet und/oder keine undokumentierten Methoden verwenden möchte:

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

Es reicht aus, einen Vanilla-View-Controller zu präsentieren und zu entlassen.

Offensichtlich müssen Sie immer noch die Orientierung in Ihrer Überschreibung von shouldAutorotateToInterfaceOrientation bestätigen oder ablehnen. Dies führt jedoch dazu, dass shouldAutorotate ... vom System erneut aufgerufen wird.

101
Josh

Soweit ich das beurteilen kann, funktioniert die setOrientation:-Methode nicht (oder funktioniert vielleicht nicht mehr). Folgendes mache ich dazu:

zuerst setzen Sie diese Definition oben in Ihre Datei, direkt unter Ihren #imports:

#define degreesToRadian(x) (M_PI * (x) / 180.0)

dann in der viewWillAppear:-Methode

[[UIApplication sharedApplication] setStatusBarHidden:YES animated:NO];     
if (self.interfaceOrientation == UIInterfaceOrientationPortrait) {  
    self.view.transform = CGAffineTransformIdentity;
    self.view.transform = CGAffineTransformMakeRotation(degreesToRadian(90));
    self.view.bounds = CGRectMake(0.0, 0.0, 480, 320);
}

wenn Sie möchten, dass das animiert wird, können Sie das Ganze in einen Animationsblock einwickeln, z.

[UIView beginAnimations:@"View Flip" context:nil];
[UIView setAnimationDuration:1.25];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];

[[UIApplication sharedApplication] setStatusBarHidden:YES animated:NO];     
if (self.interfaceOrientation == UIInterfaceOrientationPortrait) {  
    self.view.transform = CGAffineTransformIdentity;
    self.view.transform = CGAffineTransformMakeRotation(degreesToRadian(90));
    self.view.bounds = CGRectMake(0.0, 0.0, 480, 320);
}
[UIView commitAnimations];

Dann können Sie in Ihrem Portrait-Modus-Controller die Umkehrung durchführen. Überprüfen Sie, ob sich der Controller derzeit im Querformat befindet. Wenn ja, drehen Sie ihn zurück in Portrait.

16
Bdebeez

Wenn Sie ihn zwingen möchten, sich vom Hochformat in das Querformat zu drehen, finden Sie hier den Code. Beachten Sie, dass Sie die Mitte Ihrer Ansicht anpassen müssen. Ich bemerkte, dass meine Ansicht nicht den richtigen Platz einnahm. Ansonsten hat es perfekt funktioniert. Danke für den Tipp.

if(UIInterfaceOrientationIsLandscape(self.interfaceOrientation)){

        [UIView beginAnimations:@"View Flip" context:nil];
        [UIView setAnimationDuration:0.5f];
        [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];

        self.view.transform = CGAffineTransformIdentity;
        self.view.transform = CGAffineTransformMakeRotation(degreesToRadian(90));
        self.view.bounds = CGRectMake(0.0f, 0.0f, 480.0f, 320.0f);
        self.view.center = CGPointMake(160.0f, 240.0f);

        [UIView commitAnimations];
}
16
Michael Gaylord

Ich habe gegraben und gesucht und nach einer guten Lösung dafür gesucht. Diesen Blogeintrag mit dem Trick gefunden: Entfernen Sie Ihre äußerste Ansicht aus dem Schlüssel UIWindow und fügen Sie sie erneut hinzu. Anschließend fragt das System die shouldAutorotateToInterfaceOrientation:-Methoden erneut von Ihren Viewcontrollern ab und erzwingt die korrekte Ausrichtung, die angewendet werden soll .. iphone zwingt uiview zur Neuausrichtung

7
nobre

Es gibt eine einfache Möglichkeit, das iPhone programmatisch auf die erforderliche Ausrichtung zu bringen - mithilfe von zwei der bereits bereitgestellten Antworten von kdbdallas , Josh :

//will rotate status bar
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight];


//will re-rotate view according to statusbar
UIViewController *c = [[UIViewController alloc]init];
[self presentModalViewController:c animated:NO];
[self dismissModalViewControllerAnimated:NO];
[c release];

klappt wunderbar :)

BEARBEITEN:

für iOS 6 muss ich diese Funktion hinzufügen: (funktioniert auf modalem Viewcontroller)

- (NSUInteger)supportedInterfaceOrientations
{
    return (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight);
}
7

Ich hatte ein Problem, bei dem ich eine UIViewController auf dem Bildschirm in einer UINavigationController in Querformat hatte. Wenn der Next View Controller im Fluss gedrückt wird, brauchte ich jedoch das Gerät, um zur Hochformatausrichtung zurückzukehren.

Was mir aufgefallen ist, war, dass die shouldAutorotateToInterfaceOrientation:-Methode nicht aufgerufen wird, wenn ein neuer View-Controller auf den Stack geschoben wird, sondern es wird aufgerufen, wenn ein View-Controller aus dem Stack entnommen wird .

Ich nutze diesen Codeausschnitt in einer meiner Apps:

- (void)selectHostingAtIndex:(int)hostingIndex {

    self.transitioning = YES;

    UIViewController *garbageController = [[[UIViewController alloc] init] autorelease];
    [self.navigationController pushViewController:garbageController animated:NO];
    [self.navigationController popViewControllerAnimated:NO];

    BBHostingController *hostingController = [[BBHostingController alloc] init];
    hostingController.hosting = [self.hostings objectAtIndex:hostingIndex];
    [self.navigationController pushViewController:hostingController animated:YES];
    [hostingController release];

    self.transitioning = NO;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    if (self.transitioning)
        return (toInterfaceOrientation == UIInterfaceOrientationPortrait);
    else
        return YES;
}

Wenn Sie einen leeren View-Controller erstellen, ihn auf den Stapel schieben und ihn sofort abnehmen, ist es grundsätzlich möglich, die Benutzeroberfläche in die Hochformatposition zu bringen. Nachdem der Controller geknackt wurde, drücke ich einfach den Controller, den ich vorgeben wollte. Optisch sieht es gut aus - der leere, beliebige View-Controller wird vom Benutzer nie gesehen.

7
Andrew Vilcsak

Joshs Antwort funktioniert gut für mich.

Ich ziehe es jedoch vor, eine "Ausrichtung geändert zu haben, bitte aktualisieren Sie die Benutzeroberfläche". Wenn diese Benachrichtigung von einem Ansichtscontroller empfangen wird, ruft er shouldAutorotateToInterfaceOrientation: auf. Sie können eine beliebige Ausrichtung festlegen, indem Sie YES für die gewünschte Ausrichtung zurückgeben.

[[NSNotificationCenter defaultCenter] postNotificationName:UIDeviceOrientationDidChangeNotification object:nil];

Das einzige Problem ist, dass dies eine Neuorientierung ohne eine Animation erzwingt. Sie müssen diese Zeile zwischen beginAnimations: und commitAnimations umschließen, um einen reibungslosen Übergang zu erreichen.

Hoffentlich hilft das.

5

FWIW, hier ist meine Implementierung der manuellen Ausrichtungseinstellung (um in den Root-View-Controller Ihrer App zu gelangen, natch): 

-(void)rotateInterfaceToOrientation:(UIDeviceOrientation)orientation{

    CGRect bounds = [[ UIScreen mainScreen ] bounds ];
    CGAffineTransform t;
    CGFloat r = 0;
    switch ( orientation ) {
        case UIDeviceOrientationLandscapeRight:
            r = -(M_PI / 2);
            break;
        case UIDeviceOrientationLandscapeLeft:
            r  = M_PI / 2;
            break;
    }
    if( r != 0 ){
        CGSize sz = bounds.size;
        bounds.size.width = sz.height;
        bounds.size.height = sz.width;
    }
    t = CGAffineTransformMakeRotation( r );

    UIApplication *application = [ UIApplication sharedApplication ];

    [ UIView beginAnimations:@"InterfaceOrientation" context: nil ];
    [ UIView setAnimationDuration: [ application statusBarOrientationAnimationDuration ] ];
    self.view.transform = t;
    self.view.bounds = bounds;
    [ UIView commitAnimations ];

    [ application setStatusBarOrientation: orientation animated: YES ];     
}

gekoppelt mit der folgenden UINavigationControllerDelegate-Methode (vorausgesetzt, Sie verwenden einen UINavigationController):

-(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
    // rotate interface, if we need to
    UIDeviceOrientation orientation = [[ UIDevice currentDevice ] orientation ];
    BOOL bViewControllerDoesSupportCurrentOrientation = [ viewController shouldAutorotateToInterfaceOrientation: orientation ];
    if( !bViewControllerDoesSupportCurrentOrientation ){
        [ self rotateInterfaceToOrientation: UIDeviceOrientationPortrait ];
    }
}

Das sorgt dafür, dass die Root-Ansicht gedreht wird, je nachdem, ob ein eingehender UIViewController die aktuelle Geräteorientierung unterstützt. Schließlich möchten Sie rotateInterfaceToOrientation mit den tatsächlichen Änderungen der Geräteorientierung verknüpfen, um die Standardfunktionen von iOS nachzuahmen. Fügen Sie diesen Ereignishandler demselben Root-View-Controller hinzu:

-(void)onUIDeviceOrientationDidChangeNotification:(NSNotification*)notification{
    UIViewController *tvc = self.rootNavigationController.topViewController;
    UIDeviceOrientation orientation = [[ UIDevice currentDevice ] orientation ];
    // only switch if we need to (seem to get multiple notifications on device)
    if( orientation != [[ UIApplication sharedApplication ] statusBarOrientation ] ){
        if( [ tvc shouldAutorotateToInterfaceOrientation: orientation ] ){
            [ self rotateInterfaceToOrientation: orientation ];
        }
    }
}

Registrieren Sie sich schließlich für UIDeviceOrientationDidChangeNotification-Benachrichtigungen in init oder loadview wie folgt:

[[ NSNotificationCenter defaultCenter ] addObserver: self
                                           selector: @selector(onUIDeviceOrientationDidChangeNotification:)
                                               name: UIDeviceOrientationDidChangeNotification
                                             object: nil ];
[[ UIDevice currentDevice ] beginGeneratingDeviceOrientationNotifications ];
3
Henry Cooke

Das funktioniert für mich (danke Henry Cooke):

Ziel war es, mich nur mit Änderungen der Landschaftsorientierung zu befassen.

init-Methode:

[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(orientationChanged:)
                                             name:UIDeviceOrientationDidChangeNotification
                                           object:nil];

- (void)orientationChanged:(NSNotification *)notification {    
    //[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
    UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;
    CGRect bounds = [[ UIScreen mainScreen ] bounds ];
    CGAffineTransform t;
    CGFloat r = 0;
    switch ( orientation ) {
        case UIDeviceOrientationLandscapeRight:
            r = 0;
            NSLog(@"Right");
            break;
        case UIDeviceOrientationLandscapeLeft:
            r  = M_PI;
            NSLog(@"Left");
            break;
        default:return;
    }

    t = CGAffineTransformMakeRotation( r );

    UIApplication *application = [ UIApplication sharedApplication ];
    [ UIView beginAnimations:@"InterfaceOrientation" context: nil ];
    [ UIView setAnimationDuration: [ application statusBarOrientationAnimationDuration ] ];
    self.view.transform = t;
    self.view.bounds = bounds;
    [ UIView commitAnimations ];

    [ application setStatusBarOrientation: orientation animated: YES ];
}
2
user324168

Ich habe eine App, bei der ich die Gerätedrehung in bestimmten Ansichten unterstützen möchte, andere sind jedoch im Landschaftsmodus nicht besonders sinnvoll. Wenn Sie also die Ansichten austauschen, möchte ich, dass die Drehung auf Hochformat gesetzt wird.

Ich stelle fest, dass der obige ursprüngliche Beitrag in diesem Thread jetzt sehr alt ist, aber ich hatte ein ähnliches Problem - dh. Alle Bildschirme in meiner App sind nur im Hochformat, mit Ausnahme eines Bildschirms, der vom Benutzer zwischen Querformat und Hochformat gedreht werden kann.

Dies war unkompliziert, aber wie auch bei anderen Beiträgen wollte ich, dass die App unabhängig von der aktuellen Ausrichtung des Geräts automatisch zum Portrait zurückkehrt, wenn zum vorherigen Bildschirm zurückgekehrt wird.

Die von mir implementierte Lösung bestand im Ausblenden der Navigationsleiste im Querformat, sodass der Benutzer nur im Hochformat zu vorherigen Bildschirmen zurückkehren kann. Daher können alle anderen Bildschirme nur im Hochformat sein.

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)pInterfaceOrientation {
    BOOL lHideNavBar = self.interfaceOrientation == UIInterfaceOrientationPortrait ? NO : YES;
    [self.navigationController setNavigationBarHidden:lHideNavBar animated:YES];
}

Dies hat auch den zusätzlichen Vorteil für meine App, dass im Querformat mehr Bildschirmfläche zur Verfügung steht. Dies ist hilfreich, da der fragliche Bildschirm zur Anzeige von PDF -Dateien verwendet wird.

Hoffe das hilft.

1
stephencampbell

iOS 6 Lösung:

[[[self window] rootViewController] presentViewController:[[UIViewController alloc] init] animated:NO completion:^{
    [[[self window] rootViewController] dismissViewControllerAnimated:NO completion:nil];
}];

Der genaue Code hängt von der App ab und auch davon, wo Sie sie platzieren (ich habe ihn in meiner AppDelegate verwendet). Ersetzen Sie [[self window] rootViewController] durch das, was Sie verwenden. Ich habe eine UITabBarController verwendet.

1
Bo A

Ich habe das am Ende ziemlich leicht gelöst. Ich habe alle oben genannten Vorschläge ausprobiert und kam immer noch zu kurz, daher war dies meine Lösung:

Im ViewController, der Landscape (Left oder Right) bleiben muss, warte ich auf Orientierungsänderungen:

    [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(didRotate:)
                                             name:UIDeviceOrientationDidChangeNotification object:nil];

Dann in didRotate:

- (void) didRotate:(NSNotification *)notification
{   if (orientationa == UIDeviceOrientationPortrait) 
    {
        if (hasRotated == NO) 
        {
            NSLog(@"Rotating to portait");
            hasRotated = YES;
            [UIView beginAnimations: @"" context:nil];
            [UIView setAnimationDuration: 0];
            self.view.transform = CGAffineTransformIdentity;
            self.view.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(-90));
            self.view.bounds = CGRectMake(0.0f, 0.0f, 480.0f, 320.0f);
            self.view.frame = CGRectMake(0.0f, 0.0f, 480.0f, 320.0f);
            [UIView commitAnimations];

    }
}
else if (UIDeviceOrientationIsLandscape( orientationa))
{
    if (hasRotated) 
    {
        NSLog(@"Rotating to lands");
        hasRotated = NO;
        [UIView beginAnimations: @"" context:nil];
        [UIView setAnimationDuration: 0];
        self.view.transform = CGAffineTransformIdentity;
        self.view.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(0));
        self.view.bounds = CGRectMake(0.0f, 0.0f, 320.0f, 480.0f);
        self.view.frame = CGRectMake(0.0f, 0.0f, 320.0f, 480.0f);
        [UIView commitAnimations];

    }
}

Denken Sie an alle Super Views/Subviews, die autoresizing verwenden, da view.bounds/frame explizit zurückgesetzt wird ... 

Der einzige Nachteil dieser Methode, die Ansichtslandschaft beizubehalten, ist die inhärente Animation, die zwischen den Ausrichtungen wechseln muss, wenn es besser wäre, wenn sie scheinbar keine Änderung aufweist. 

1
mrdavenz

Ich habe eine Lösung gefunden und etwas auf Französisch geschrieben (aber der Code ist auf Englisch). Hier

Die Möglichkeit besteht darin, den Controller der Fensteransicht hinzuzufügen (der Controller muss über eine gute Implementierung der Funktion shouldRotate ... verfügen).

0
Vinzius