webentwicklung-frage-antwort-db.com.de

Wie kann ich zulassen, dass sich nur ein einzelner UIViewController in Quer- und Hochrichtung dreht?

Meine App ist nur für iphone Geräte (sowohl für das iPhone 4 als auch für das iPhone 5) und unterstützt nur ios 6.

Meine gesamte App unterstützt nur den portrait -Modus. Aber es gibt eine Ansicht namens "ChatView", die ich sowohl landscape als auch portrait unterstützen möchte.

Ich habe die erforderlichen Gerätedrehungen wie folgt eingestellt:

enter image description here

Ich habe auch versucht, folgenden Code, um die Rotation in "ChatView" zu unterstützen -

-(BOOL)shouldAutorotate
{
    return YES;
}

-(NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskLandscape;
}

Aber diese Ansicht konnte nicht gedreht werden.

Ich habe viel danach gesucht, konnte aber keine Lösung für mein Problem finden.

Und auch in "ChatView" gibt es einige Objekte wie Buttons, Textfelder, deren Frames programmatisch gesetzt werden. Ich möchte also wissen, ob ich die Rahmen all dieser Objekte auch für den Querformatmodus festlegen muss.

Bitte hilf mir.

Vielen Dank.....

60
Rohan

Ich denke, wenn Sie nur eine Viewcontroller-Drehung unterstützen möchten, ist dies nicht möglich, da die Anwendung den von Ihnen in der Datei .plist Festgelegten Ausrichtungen folgt. Eine Alternative, die Sie befolgen können, besteht darin, Ihre App sowohl für Quer- als auch für Hochformat zu unterstützen und alle Rotationen der Ansichtskontroller in Hochformat mit Ausnahme der Chat-Ansicht einzufrieren.

EDIT

Um eine Unterklasse von UINavigationController zu erstellen, erstellen Sie eine neue Datei mit dem Namen, z. CustomNavigationController und mache es zu einer Unterklasse von UINavigationController.

. h Datei

#import <UIKit/UIKit.h>

@interface CustomNavigationController : UINavigationController

@end

.m Datei

#import "CustomNavigationController.h"

@interface CustomNavigationController ()

@end


@implementation CustomNavigationController

-(BOOL)shouldAutorotate
{
    return NO;
}

-(UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskAll;
}


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

@end

Setzen Sie die Klasse Ihres UINavigationController in Ihrer Hauptklasse xib auf CustomNavigationController. Hoffe es hilft dir ..

28
NightFury

Einfach, aber es funktioniert sehr gut. IOS 7.1 und 8

AppDelegate.h

@property () BOOL restrictRotation;

AppDelegate.m

-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if(self.restrictRotation)
    return UIInterfaceOrientationMaskPortrait;
else
    return UIInterfaceOrientationMaskAll;
}

ViewController

-(void) restrictRotation:(BOOL) restriction
{
    AppDelegate* appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
    appDelegate.restrictRotation = restriction;
}

viewDidLoad

[self restrictRotation:YES]; or NO
63
Alan10977

Ihr View Controller dreht sich niemals in eine Position, die von der App selbst nicht unterstützt wird. Sie sollten alle möglichen Rotationen aktivieren und dann in Ansichtscontrollern, die nicht rotieren sollen, die folgenden Zeilen einfügen

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

In ChatView sollte es sein:

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskAll;
}

Wenn Sie Ihr Layout nach einer Drehung ändern müssen, sollten Sie die entsprechenden Änderungen an Ihren Unteransichten in implementieren

- (void)viewWillLayoutSubviews

Verwenden self.view.bounds, um die aktuelle Größe von view zu überprüfen, seit self.view.frame ändert sich nach Rotationen nicht.

21
johnyu

für das spezifische viewcontroller.m Sie möchten drehen

füge diese Methode hinzu:

- (BOOL)canAutoRotate
{
    return YES;
}

dann in deinem AppDelegate.m

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
    UIViewController *currentViewController = [self topViewController];

    if ([currentViewController respondsToSelector:@selector(canAutoRotate)]) {
        NSMethodSignature *signature = [currentViewController methodSignatureForSelector:@selector(canAutoRotate)];

        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];

        [invocation setSelector:@selector(canAutoRotate)];
        [invocation setTarget:currentViewController];

        [invocation invoke];

        BOOL canAutorotate = NO;
        [invocation getReturnValue:&canAutorotate];

        if (canAutorotate) {
            return UIInterfaceOrientationMaskAll;
        }
    }

    return UIInterfaceOrientationMaskPortrait;
}

- (UIViewController *)topViewController
{
    return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}

- (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;
    }
}
16
Ted

Teds Antwort passt gut zu dem von Alexander von Norwegen angesprochenen Thema. Aber ich dachte mir, dass das Problem nicht so ist, wie Alexander es erklärt hat.

Wenn ViewController B im Querformat (Alle Ausrichtungen aktiviert) wieder zu ViewController A zurückkehrt (nur Hochformat), nachdem der Benutzer auf die Schaltfläche Zurück geklickt hat, wird supportedInterfaceOrientationsForWindow nicht aufgerufen und ViewController A wird im Querformat angezeigt

Tatsächlich kehrt ViewController B im Querformat (Alle Ausrichtungen aktiviert) zu ViewController A (nur Hochformat) zurück, nachdem der Benutzer auf die Zurück-Schaltfläche Appdelegate geklickt hat

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation;

wird gerufen. Der Root-View-Controller ist jedoch ViewController B (dieser rotationsfähige View-Controller). ViewController A kehrt nicht zum Hochformat zurück, da ViewController B immer noch zurückkehrt

-(BOOL)shouldAutorotate{

    return YES;
}

Wenn Sie also die Zurück-Taste drücken, wird in ViewController B "shouldAutorotate -> NO" angezeigt. Dann wechselt ViewController A zum Hochformat. Das habe ich getan

@property (nonatomic, assign) BOOL canAutoRotate;

#pragma mark - Public methods
- (BOOL)canAutoRotate
{
    return _canAutoRotate;
}

#pragma mark - Button actions
- (void)backButtonPressed:(UIButton *)sender {
    _canAutoRotate = NO;
   (...)
}

#pragma mark - Init
- (id)init{
    if(self=[super init]) {
        _canAutoRotate = YES;
    }
    return self;
}
4

Swift 3 Kosher Version

Ich habe das hier nur für einen Fall gelassen, bei dem jemand das Problem hat.

Apples Dokumentation für supportedInterfaceOrientations sagt:

Wenn der Benutzer die Geräteorientierung ändert, ruft das System diese Methode auf dem Stammansichts-Controller oder dem obersten angezeigten Ansichts-Controller auf, der das Fenster ausfüllt. Wenn der Ansichts-Controller die neue Ausrichtung unterstützt, werden das Fenster und der Ansichts-Controller in die neue Ausrichtung gedreht. Diese Methode wird nur aufgerufen, wenn die shouldAutorotate-Methode des View-Controllers true zurückgibt.

In wenigen Worten müssen Sie supportedInterfaceOrientations im Stammansichts-Controller überschreiben, damit er den Wert für den obersten untergeordneten Ansichtscontroller und ansonsten den Standardwert zurückgibt.

Prüfen Sie, ob die App alle Modi unterstützt (siehe Bereitstellungsinformationen in den allgemeinen Zieleinstellungen oder Info.plist), und ermitteln Sie die Klasse Ihres Root-View-Controllers. Dies kann eine generische UIViewController, UINavigationController, UITabBarController oder eine benutzerdefinierte Klasse sein. Sie können es auf diese Weise überprüfen:

dump(UIApplication.shared.keyWindow?.rootViewController)

Oder wie Sie möchten.

Lass es etwas CustomNavigationController sein. Also solltest du supportedInterfaceOrientations wie folgt überschreiben:

class CustomNavigationController: UINavigationController {

    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return topViewController?.supportedInterfaceOrientations ?? .allButUpsideDown
    }
}

In jedem Ansichtscontroller, der nur die Ausrichtung im Hochformat unterstützen soll, überschreiben Sie supportedInterfaceOrientations folgendermaßen:

class ChildViewController: UIViewController {

    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return .portrait
    }
}

Vergessen Sie dann nicht zu prüfen, ob shouldAutorotate von Ihrem Root-View-Controller und dem obersten präsentierten View-Controller bereits true zurückgibt. Wenn nicht, fügen Sie dies zu den Klassendefinitionen hinzu:

override var shouldAutorotate: Bool {
    return true
}

Andernfalls wird supportedInterfaceOrientations überhaupt nicht aufgerufen.

Bitte schön!

Wenn Sie das umgekehrte Problem beheben müssen, wenn nur ein Ansichtscontroller eine Reihe von Ausrichtungen unterstützen soll, und andere nicht, nehmen Sie diese Änderungen an jedem Ansichtscontroller außer diesem vor.

Hoffe das wird helfen.

2
Artem Kirillov

Ich bin mir nicht sicher über den Verlauf dieses Problems (jetzt = Zeitrahmen für iOS 10), aber die einfachste Lösung fehlte, als ich dies gepostet habe im Oktober 2016.

Vorausgesetzt, Sie möchten dies:

  1. Unterstützt iOS 7 und nur neuer (einschließlich iOS 10)
  2. Einige Ansichtscontroller sollten alle Ausrichtungen unterstützen, andere sollten eine Teilmenge von Ausrichtungen unterstützen. Beispiel für das, was ich meine: Ein Ansichtscontroller sollte nur Hochformat unterstützen, während alle anderen alle Ausrichtungen unterstützen sollten
  3. Alle Ansichtscontroller müssen sich automatisch drehen, wenn sie die Drehung unterstützen (dh, Sie möchten nicht den Code, der dieses Problem in Ihren Ansichtscontrollern behebt).
  4. Unterstützung für das Hinzufügen von UINavigationControllers in XIBs/NIBs/Storyboards, ohne dass Sie etwas tun müssen

... dann (IMO) ist die einfachste Lösung: mache ein UINavigationControllerDelegate, NICHT eine Unterklasse von UINavigationController (was gegen Annahme 4 oben verstößt).

Als ich das gelöst habe, habe ich beschlossen, mein erstes ViewController ein UINavigationControllerDelegate zu machen. Dieser Ansichtscontroller legt sich selbst als Stellvertreter des Navigationscontrollers fest und gibt zurück, welche Ausrichtungen zulässig sind. In meinem Fall ist die Standardeinstellung, dass alle Ausrichtungen zulässig sind, wobei Porträt bevorzugt wird, in einem bestimmten Fall ist jedoch nur Porträt zulässig. Der folgende Code stammt von Swift 3/XCode 8:

    class iPhoneStartViewController: UIViewController {

        var navInterfaceOrientationMask: UIInterfaceOrientationMask?
        var navInterfaceOrientationPreferred: UIInterfaceOrientation! = .portrait

        override func viewDidLoad() {
            super.viewDidLoad()
            self.navigationController?.delegate = self
        }

        @IBAction func cameraButtonPressed(_ sender: AnyObject) {
            if PermissionsHelper.singleton().photosPermissionGranted() == false {
                self.navInterfaceOrientationMask = nil   // default is: all orientations supported
                self.performSegue(withIdentifier: "segueToPhotoAccess", sender: self)
            } else {
                self.navInterfaceOrientationMask = .portrait // this stops the next view controller from being to rotate away from portrait
                self.performSegue(withIdentifier: "segueToCamera", sender: self)
            }
        }
     }

     // lock orientation to portrait in certain cases only. Default is: all orientations supported
    extension iPhoneStartViewController : UINavigationControllerDelegate {
        public func navigationControllerSupportedInterfaceOrientations(_ navigationController: UINavigationController) -> UIInterfaceOrientationMask {
            if let mask = self.navInterfaceOrientationMask {
                return mask
            } else {
                return .all
            }
        }

        public func navigationControllerPreferredInterfaceOrientationForPresentation(_ navigationController: UINavigationController) -> UIInterfaceOrientation {
            return self.navInterfaceOrientationPreferred
        }
    }
2
xaphod

erstellen Sie eine Unterklasse von UINavigationController wie folgt:

MyNavigationController.h

#import <UIKit/UIKit.h>

@interface MyNavigationController : UINavigationController

@end

MyNavigationController.m

#import "MyNavigationController.h"
#import "ServicesVC.h"

@implementation MyNavigationController

-(BOOL)shouldAutorotate{

    return YES;
}

-(NSUInteger)supportedInterfaceOrientations{

    if ([[self.viewControllers lastObject] isKindOfClass:[ServicesVC class]]) {
        return UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight;
    }

    return UIInterfaceOrientationMaskAll;
}

@end

vorausgesetzt, Ihr Viewcontroller heißt: ServicesVC

1
Jesus

Basierend auf der Antwort von @ iAnum habe ich die Erkennung von Autorotate- und UIViewController-Klassen aktiviert.

Dies liegt daran, dass beim Wechseln in den "Special View Controller" und aus dem "Special View Controller" die Ausrichtung im Hochformat nicht korrekt ist und Sie in einer nicht unterstützten Ausrichtung stecken bleiben.

Ich hatte nur eine Ansicht, die Querformat unterstützt, und habe sie daher im benutzerdefinierten Navigations-Ansichtscontroller fest programmiert:

-(BOOL)shouldAutorotate
{
    return YES;
}

-(NSUInteger)supportedInterfaceOrientations
{
    //Access the current top object.
    UIViewController *viewController = [self.viewControllers lastObject];
    //Is it one of the landscape supported ones?
    if ([viewController isMemberOfClass:[SpecialViewController class]]) {
        return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight;
    } else
        return UIInterfaceOrientationMaskPortrait;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    //Access the current top object.
    UIViewController *viewController = [self.viewControllers lastObject];
    //Is it one of the landscape supported ones?
    if ([viewController isMemberOfClass:[SpecialViewController class]]) {
        return interfaceOrientation;
    } else
        return UIInterfaceOrientationIsPortrait(interfaceOrientation);
}

Es gibt ein Problem beim Poppen von VCs, das hier besprochen wird https://stackoverflow.com/a/15057537/127735 wobei das Zurückdrücken im Querformat nicht einmal die Ausrichtungsmethoden aufruft, also müssen Sie es hacken ein bisschen durch Zeigen und Schließen einer modalen Ansicht.

Und denken Sie dann daran, dass Sie, wenn willShowViewController ausgelöst werden soll, self.delegate = self festlegen und das UINavigationControllerDelegate zusammen mit dem folgenden Code zu Ihrem benutzerdefinierten Navigationscontroller hinzufügen müssen.

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return UIInterfaceOrientationPortrait;
}

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    UIApplication* application = [UIApplication sharedApplication];
    if (application.statusBarOrientation != UIInterfaceOrientationPortrait)
    {
        UIViewController *c = [[UIViewController alloc]init];
        [c.view setBackgroundColor:[UIColor clearColor]];
        [navigationController presentViewController:c animated:NO completion:^{
            [self dismissViewControllerAnimated:YES completion:^{
            }];
        }];
    }
}
1
LordParsley

Hier ist die Antwort von Alexander ( https://stackoverflow.com/posts/25507963/revisions ) in Swift:

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {

    var currentViewController: UIViewController? = self.topViewController()
    if currentViewController != nil && currentViewController!.canAutoRotate() {
        return Int(UIInterfaceOrientationMask.All.rawValue)
    }
    return Int(UIInterfaceOrientationMask.Portrait.rawValue)


}

func topViewController() -> UIViewController? {
    if UIApplication.sharedApplication().keyWindow != nil
    {
        return self.topViewControllerWithRootViewController(UIApplication.sharedApplication().keyWindow!.rootViewController!)
    }
    return nil
}

func topViewControllerWithRootViewController(rootViewController: UIViewController?) -> UIViewController? {
    if rootViewController == nil {
        return nil
    }
    if rootViewController!.isKindOfClass(UITabBarController) {
        var tabBarController: UITabBarController = (rootViewController as? UITabBarController)!
        return self.topViewControllerWithRootViewController(tabBarController.selectedViewController)
    }
    else {
        if rootViewController!.isKindOfClass(UINavigationController) {
            var navigationController: UINavigationController = (rootViewController as? UINavigationController)!
            return self.topViewControllerWithRootViewController(navigationController.visibleViewController)
        }
        else {
            if (rootViewController!.presentedViewController != nil) {
                var presentedViewController: UIViewController = rootViewController!.presentedViewController!
                return self.topViewControllerWithRootViewController(presentedViewController)
            }
            else {
                return rootViewController
            }
        }
    }
}

Darüber hinaus müssen Sie das folgende Snippet in AppDelegate.Swift hinzufügen:

extension UIViewController {
func canAutoRotate() -> Bool {
    return false
}}

Und für ViewController, für die Sie alle Rotationen zulassen möchten, fügen Sie diese Funktion hinzu:

override func canAutoRotate() -> Bool {
    return true
}
1
egsemsem

// Diese Methode in die App Deligate-Klasse einfügen

- (UIInterfaceOrientationMask)application:(UIApplication )application supportedInterfaceOrientationsForWindow:(UIWindow )window
{
 if ([self.window.rootViewController.presentedViewController isKindOfClass: [_moviePlayerController class]])
  {
   if (self.window.rootViewController.presentedViewController)
        return UIInterfaceOrientationMaskAll;
    else return UIInterfaceOrientationMaskPortrait;
  }
 else return UIInterfaceOrientationMaskPortrait;
}   
0
dheerendra

Wenn die App von IOS7 bis IOS9 unterstützt, verwenden Sie diesen Code zur Orientierung:

#if __IPHONE_OS_VERSION_MAX_ALLOWED < 90000
- (NSUInteger)supportedInterfaceOrientations
#else
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
#endif
{
    if([AppDelegate isPad]) return UIInterfaceOrientationMaskAll;
    else return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
}
0
Mihir Oza

Ich weiß, dass diese Fragen sehr alt sind, aber es bedarf einer aktualisierten Antwort. Der einfachste und korrekteste Weg, um dieses Ergebnis zu erzielen, ist die Aktivierung von Hoch- und Querformat in Ihren App-Einstellungen. Fügen Sie dann Ihrem App-Delegaten diesen Code hinzu:

 func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {

    if let navigationController = self.window?.rootViewController as? UINavigationController {

        if navigationController.visibleViewController is INSERTYOURVIEWCONTROLLERHERE  {
            return UIInterfaceOrientationMask.All
        }

        else {
            return UIInterfaceOrientationMask.Portrait
        }
    }

    return UIInterfaceOrientationMask.Portrait
}

Vergessen Sie nicht, "INSERTYOURVIEWCONTROLLERHERE" durch Ihren View Controller zu ersetzen.

0
Paul Lehn

Ich hatte die gleiche Situation. Also habe ich UINavigationController in CustomNavigationController unterteilt und in diesem CustomNavigationController geschrieben

#define IOS_OLDER_THAN_6 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] < 6.0 )
#define IOS_NEWER_OR_EQUAL_TO_6 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] >= 6.0 )


#pragma mark - Rotation

#ifdef IOS_OLDER_THAN_6
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
      return (toInterfaceOrientation == UIInterfaceOrientationPortrait);
}
#endif
#ifdef IOS_NEWER_OR_EQUAL_TO_6
-(BOOL)shouldAutorotate {
    return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;;
}
#endif

Ich habe diesen CustomNavigationController anstelle des vorhandenen NavigationControllers verwendet.

Dann habe ich innerhalb des View Controllers, den Sie in LandScape Orientation anzeigen müssen, LandScapeView geschrieben

#pragma mark - Rotation

#ifdef IOS_OLDER_THAN_6

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
    return (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight | toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}

#endif

#ifdef IOS_NEWER_OR_EQUAL_TO_6

-(BOOL)shouldAutorotate {
    return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskLandscapeLeft;
}

#endif

In CustomNavigationController präsentierte ich diesen Ansichtscontroller, der nicht in den Navigationsstapel verschoben wurde. So erschien der LandScapeView in LandScape Orientation.

LandScapeView *graph = [[LandScapeView alloc]init....];
[self presentViewController:graph animated:YES completion:nil];

Ich habe nichts an der Supported Interface Orientation in den Projekteinstellungen geändert.

0
rakeshNS