Jak wymusić UIViewController na orientację pionową w systemie iOS 6


85

Ponieważ ShouldAutorotateToInterfaceOrientationjest on przestarzały w iOS 6 i użyłem go do wymuszenia tylko portretu określonego widoku , jaki jest właściwy sposób zrobienia tego w iOS 6? Dotyczy to tylko jednego obszaru mojej aplikacji, wszystkie inne widoki mogą się obracać.

Odpowiedzi:


117

Jeśli chcesz, aby wszystkie nasze kontrolery nawigacyjne szanowały kontroler widoku z góry, możesz użyć kategorii, aby nie musieć przeglądać i zmieniać wielu nazw klas.

@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

Jak wskazuje kilka komentarzy, jest to szybkie rozwiązanie problemu. Lepszym rozwiązaniem jest podklasa UINavigationController i umieszczenie tam tych metod. Podklasa pomaga również w obsłudze 6 i 7.


3
Mogę potwierdzić, że to działa. Jeśli chcesz, możesz również zamienić „[self.viewControllers lastObject]” na „self.topViewController”.
Wayne Liu

3
Jeśli używasz UITabBarController, ta kategoria UINavigationController nie pomoże. Zamiast tego powinieneś utworzyć kategorię na UITabBarController ...
Borut Tomazin

46
Problem z tym rozwiązaniem polega na tym, że nie działa, gdy wyskakujesz kontroler, który był w poziomie, a twój nowy górny kontroler obsługuje tylko portret (lub odwrotnie), te wywołania zwrotne nie są wywoływane w tym przypadku i jeszcze nie znalazłem sposobu, jak to zrobić wymuś poprawną orientację nowego górnego kontrolera. Jakieś pomysły?
Lope

4
Podklasę UINavigationController ustawiłem jako window.rootController. Zaimplementowałem wszystkie 3 metody, działa świetnie, gdy zmieniasz obrót urządzenia, problem w tym, że te metody (i nic związanego z obrotem) są wywoływane po wyskakującym kontrolerze
Lope

4
Jeśli robię push lub pop z kontrolera widoku poziomego, to wymusza UIViewController zmienia się w krajobraz. Jeśli jednak obrócę do portretu, to działa dobrze i nigdy nie zmieni się w krajobraz. Jedyny problem podczas wypychania lub wyskakiwania z krajobrazu. Proszę o pomoc
Tariq

63

Najlepszy sposób na iOS6 został opisany w artykule „Samouczki iOS6 By Tutorials” zespołu Ray Wenderlich - http://www.raywenderlich.com/ i UINavigationControllerw większości przypadków jest lepszy niż tworzenie podklas .

Używam iOS6 z scenorysem, który zawiera UINavigationControllerzestaw jako początkowy kontroler widoku.

//AppDelegate.m - ta metoda nie jest niestety dostępna przed 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 - zwróć dowolne orientacje, które chcesz obsługiwać dla każdej z nich UIViewController

- (NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskPortrait;
}

1
To najlepsze rozwiązanie dla iOS 6
Homam

2
@Phil, Działa dobrze na iOS 6. Ale w niektórych przypadkach, jeśli przejdziesz z krajobrazu do portretu, to nie działa. Masz jakiś pomysł, dlaczego tak się dzieje?
Kirti Nikam

1
Bardzo przydatne rozwiązanie. Dla mnie najlepsze.
oscar castellon

1
Praca na iOS 7 beta 6. Działa przy przechodzeniu z poziomego do pionowego w moim przypadku.
Martin Berger,

Jestem na iOS 6, ale to nie działa. Przerywa w wierszu „UIViewController * presentViewController”.
Marcel Marino

39

Ta odpowiedź odnosi się do pytań zadanych w komentarzach do postu PO:

Aby wymusić pojawienie się widoku w określonej orientacji, w viewWillAppear umieść następujące elementy:

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

Trochę to hack, ale to zmusza UIViewControllerdo przedstawienia portretu, nawet jeśli poprzedni kontroler był krajobrazem

UPDATE dla iOS7

Powyższe metody są teraz przestarzałe, więc w przypadku iOS 7 użyj następujących:

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:^{
            }];
     }];
}

Co ciekawe, w chwili pisania tego tekstu albo teraźniejszość, albo zwolnienie muszą być animowane. Jeśli żadna z nich nie jest, otrzymasz biały ekran. Nie mam pojęcia, dlaczego to działa, ale działa! Efekt wizualny różni się w zależności od tego, który jest animowany.


Dzięki, spróbuję, gdy znajdę kilka minut wolnego czasu
Lope

@RohanAgarwal działa zgodnie z reklamą, używam go tutaj. Ale musisz mieć również zaimplementowany kod zaakceptowanej odpowiedzi, inaczej nie zadziała.
Dennis Munsie

2
Czy ktoś wymyślił, jak sprawić, by to działało z odpowiednią animacją rotacji w tym samym czasie? To trochę irytujące, gdy widzę, jak zmienia się z portretu na krajobraz bez animacji. Działa z nadzieją, że będzie działać trochę lepiej.
Dennis Munsie

@Craig Watkinson To nie działa w scenorysie. and presentModalViewController i dismissModalViewControllerAnimated jest przestarzałe, jeśli iam używa presentVirecontroller, to nie zadziała. Please help me
Kalpesh

1
Dla ios8 odrzucenieViewControllerAnimated po prostu ulega awarii. Okazało się, że wywołanie [NWSAppDelegate sharedInstance] .window.rootViewController = nil; [NWSAppDelegate sharedInstance] .window.rootViewController = previousRootController działa dobrze.
Alexey

36

Więc napotkałem ten sam problem podczas wyświetlania portretów tylko w widokach modalnych. Normalnie utworzyłbym UINavigationController, ustawiłbym viewControllerjako rootViewController, a następnie wyświetlał UINavigationControllerjako widok modalny. Ale z iOS 6 viewControllerzapyta teraz navigationController o obsługiwane orientacje interfejsu (który domyślnie jest teraz przeznaczony dla iPada i wszystkiego, ale do góry nogami dla iPhone'a).

Rozwiązanie : musiałem podklasować UINavigationControlleri nadpisać metody autorotacji. Trochę kiepski.

- (BOOL)shouldAutorotate {
    return NO;
}

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

1
nie działa na moim. Miałem ten kod z ustawieniem globalnym na wszystkie orientacje
phil88530,

2
SupportInterfaceOrientations powinien zwracać NSUInteger, a nie BOOL. Zobacz developer.apple.com/library/ios/#feratedarticles/…
tomwhipple

zadziałało, dla mnie to tabbarcontroller, znowu dzięki za odpowiedź
otakuProgrammer

FWIW, ja też musiałem jechać tą trasą ... Nic innego nie działało. Dzięki.
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;
}

Świetny! Musi być maksymalnie na górze tego wątku. Ponieważ jest to najprostszy sposób rozwiązania problemu
Alex

@Roshan Jalgaonkar W ios 6 To nie działa dla mnie, potrzebuję tylko portretu z dolnym przyciskiem Home Jak mogę ustawić ten UIOrientation ....
Karthik

@ Karthik, aby to zadziałało, musisz włączyć obsługiwane obroty w celu swojej aplikacji.
Alejandro Iván

@ AlejandroIván k thnx
Karthik

10

Nie zgadzam się z odpowiedzią @aprato, ponieważ metody rotacji UIViewController są zadeklarowane w samych kategoriach, co powoduje niezdefiniowane zachowanie, jeśli zastąpisz to w innej kategorii. Bezpieczniej jest je zastąpić w podklasie UINavigationController (lub UITabBarController)

Nie obejmuje to również scenariusza, w którym wypychasz / prezentujesz / pop z widoku poziomego do portretu tylko VC lub odwrotnie. Aby rozwiązać ten trudny problem (nigdy nie rozwiązany przez Apple), należy:

W iOS <= 4 i iOS> = 6:

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

W iOS 5:

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

To NAPRAWDĘ zmusi UIKit do ponownej oceny wszystkich Twoich powinienAutorotate, obsługiwaneInterfaceOrientations itp.


2
Pierwsza z tych awarii u mnie niezależnie od wersji iOS. Mówi, że zwolnienie nie powinno być wzywane przed zakończeniem obecnego.
arsenius

@arsenius Czy możesz opublikować krótki opis tego, jak go używasz? Dopóki nie jest animowany, nie powinien mieć problemu, o którym wspominasz
Rafael Nobre

Umieściłem również drugi fragment w widokuDidAppear i nie pomaga to w mojej sytuacji na iOS 6. Pytanie jest tutaj: stackoverflow.com/questions/15654339/ ...
arsenius

Przepraszamy, ostatni komentarz tutaj. Przeniesienie kodu iOS 5 do viewDidAppear tworzy pewnego rodzaju nieskończoną pętlę z następującymi danymi wyjściowymi: - Przepełnienie [UIApplication beginIgnoringInteractionEvents]. Ignorowanie.
arsenius

3

Mam bardzo dobre podejście do mieszania https://stackoverflow.com/a/13982508/2516436 i 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;
    }
}

i zwróć dowolne orientacje, które chcesz obsługiwać dla każdego UIViewController

- (NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskPortrait;
}

1

Mam stosunkowo złożoną uniwersalną aplikację używającą UISplitViewController i UISegmentedController i mam kilka widoków, które muszą być przedstawione w krajobrazie przy użyciu presentViewController. Korzystając z metod sugerowanych powyżej, udało mi się sprawić, by iPhone ios 5 i 6 działał poprawnie, ale z jakiegoś powodu iPad po prostu odmówił przedstawienia jako Krajobraz. Wreszcie znalazłem proste rozwiązanie (wdrożone po wielu godzinach czytania i prób i błędów), które działa zarówno na urządzeniach, jak i na iOS 5 i 6.

Krok 1) Na kontrolerze określ wymaganą orientację (mniej więcej jak wspomniano powyżej)

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

-(BOOL)shouldAutorotate
{
    return YES;
}

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

}

Krok 2) Utwórz prostą podklasę UINavigationController i zaimplementuj następujące metody

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

Krok 3) Przedstaw swój viewController

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

Mam nadzieję, że to komuś pomoże.


1

Nie żeby tu nudno, ale czy zechciałbyś podzielić się swoją podklasą? Dziękuję Ci.

edycja: cóż, w końcu to zrobiłem, podklasa była bardzo prosta do wykonania. Po prostu musiałem zadeklarować navigationControllerw AppDelegateas UINavigationControllerSubclasszamiast domyślnej UINavigationController, a następnie zmodyfikowałem twoją podklasę za pomocą:

- (BOOL)shouldAutorotate {
    return _shouldRotate;
}

więc mogę ustawić dowolny widok, który chcę obrócić lub nie, dzwoniąc pod numer viewDidLoad

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

Mam nadzieję, że ta zmiana pomoże również innym. Dzięki za wskazówkę!

Wskazówka: skorzystaj z

- (NSUInteger)supportedInterfaceOrientations

w kontrolerach widoku, więc nie będziesz mieć pożądanego widoku portretu w poziomie lub odwrotnie.


0

Nie testowałem tego sam, ale dokumentacja stwierdza, że ​​możesz teraz zastąpić te metody: supportedInterfaceOrientationsi preferredInterfaceOrientationForPresentation.

Prawdopodobnie możesz osiągnąć to, co chcesz, ustawiając tylko taką orientację, jaką chcesz w tych metodach.


0

Odpowiedzi przy użyciu podklas lub kategorii, aby umożliwić VC w klasach UINavigationController i UITabBarController, działają dobrze. Uruchamianie trybu pionowego z poziomu kontrolera z paskiem kart nie powiodło się. Jeśli musisz to zrobić, użyj triku wyświetlania i ukrywania nieanimowanego widoku modalnego, ale zrób to w metodzie viewDidAppear . Nie działało to dla mnie w viewDidLoad lub viewWillAppear.

Poza tym powyższe rozwiązania działają dobrze.


0

W przypadku Monotouch możesz to zrobić w ten sposób:

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

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


-1

Po prostu przejdź do project.plist, a następnie dodaj Obsługiwaną orientację interfejsu, a następnie dodaj tylko Portret (dolny przycisk strony głównej) i Portret (górny przycisk strony głównej).

Możesz dodać lub usunąć tam orientację zgodnie z wymaganiami projektu.

Dzięki


1
chodzi o konkretny kontroler widoku, a nie dla całej aplikacji.
Muhammad Rizwan,

-2

1) Sprawdź ustawienia projektu i info.plist i upewnij się, że wybrano tylko te orientacje, które chcesz.

2) Dodaj następujące metody do najwyższego kontrolera widoku (kontroler nawigacji / kontroler z zakładkami)

- (NSUInteger) supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;

}

3) Dodaj następujące metody do delegata aplikacji

- (NSUInteger) supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;

}

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

}

-3

Umieść to w pliku .m każdego, ViewControllerktórego nie chcesz obracać:

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

Więcej informacji znajdziesz tutaj .

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.